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"
23 from Cura.util.bigDataStorage import BigDataStorage
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 if version.isDevVersion() and os.path.exists('C:/Program Files (x86)/Cura_14.09/CuraEngine.exe'):
38 return 'C:/Program Files (x86)/Cura_14.09/CuraEngine.exe'
39 return os.path.abspath(os.path.join(os.path.dirname(__file__), '../..', 'CuraEngine.exe'))
40 if hasattr(sys, 'frozen'):
41 return os.path.abspath(os.path.join(os.path.dirname(__file__), '../../../../..', 'CuraEngine'))
42 if os.path.isfile('/usr/bin/CuraEngine'):
43 return '/usr/bin/CuraEngine'
44 if os.path.isfile('/usr/local/bin/CuraEngine'):
45 return '/usr/local/bin/CuraEngine'
46 tempPath = os.path.abspath(os.path.join(os.path.dirname(__file__), '../..', 'CuraEngine'))
47 if os.path.isdir(tempPath):
48 tempPath = os.path.join(tempPath,'CuraEngine')
51 class EngineResult(object):
53 Result from running the CuraEngine.
54 Contains the engine log, polygons retrieved from the engine, the GCode and some meta-data.
58 self._gcodeData = BigDataStorage()
60 self._replaceInfo = {}
62 self._printTimeSeconds = None
63 self._filamentMM = [0.0] * 4
64 self._modelHash = None
65 self._profileString = profile.getProfileString()
66 self._preferencesString = profile.getPreferencesString()
67 self._gcodeInterpreter = gcodeInterpreter.gcode()
68 self._gcodeLoadThread = None
69 self._finished = False
71 def getFilamentWeight(self, e=0):
72 #Calculates the weight of the filament in kg
73 radius = float(profile.getProfileSetting('filament_diameter')) / 2
74 volumeM3 = (self._filamentMM[e] * (math.pi * radius * radius)) / (1000*1000*1000)
75 return volumeM3 * profile.getPreferenceFloat('filament_physical_density')
77 def getFilamentCost(self, e=0):
78 cost_kg = profile.getPreferenceFloat('filament_cost_kg')
79 cost_meter = profile.getPreferenceFloat('filament_cost_meter')
80 if cost_kg > 0.0 and cost_meter > 0.0:
81 return "%.2f / %.2f" % (self.getFilamentWeight(e) * cost_kg, self._filamentMM[e] / 1000.0 * cost_meter)
83 return "%.2f" % (self.getFilamentWeight(e) * cost_kg)
84 elif cost_meter > 0.0:
85 return "%.2f" % (self._filamentMM[e] / 1000.0 * cost_meter)
88 def getPrintTime(self):
89 if self._printTimeSeconds is None:
91 if int(self._printTimeSeconds / 60 / 60) < 1:
92 return '%d minutes' % (int(self._printTimeSeconds / 60) % 60)
93 if int(self._printTimeSeconds / 60 / 60) == 1:
94 return '%d hour %d minutes' % (int(self._printTimeSeconds / 60 / 60), int(self._printTimeSeconds / 60) % 60)
95 return '%d hours %d minutes' % (int(self._printTimeSeconds / 60 / 60), int(self._printTimeSeconds / 60) % 60)
97 def getFilamentAmount(self, e=0):
98 if self._filamentMM[e] == 0.0:
100 return '%0.2f meter %0.0f gram' % (float(self._filamentMM[e]) / 1000.0, self.getFilamentWeight(e) * 1000.0)
103 return self._engineLog
106 self._gcodeData.seekStart()
107 return self._gcodeData
109 def setGCode(self, gcode):
110 self._gcodeData = BigDataStorage()
111 self._gcodeData.write(gcode)
112 self._replaceInfo = {}
114 def addLog(self, line):
115 self._engineLog.append(line)
117 def setHash(self, hash):
118 self._modelHash = hash
120 def setFinished(self, result):
122 for k, v in self._replaceInfo.items():
123 self._gcodeData.replaceAtStart(k, v)
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.clone()))
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
187 for potential_port in xrange(0xC20A, 0xFFFF):
188 self._serverPortNr = potential_port
190 self._serversocket.bind(('127.0.0.1', self._serverPortNr))
193 print("Failed to listen on port: %d" % (self._serverPortNr))
195 print("Failed to listen on any port, this is a fatal error")
197 thread = threading.Thread(target=self._socketListenThread)
201 def _socketListenThread(self):
202 self._serversocket.listen(1)
203 print 'Listening for engine communications on %d' % (self._serverPortNr)
206 sock, _ = self._serversocket.accept()
207 thread = threading.Thread(target=self._socketConnectionThread, args=(sock,))
210 except socket.error, e:
211 if e.errno != errno.EINTR:
214 def _socketConnectionThread(self, sock):
224 cmd = struct.unpack('@i', data)[0]
225 if cmd == self.GUI_CMD_REQUEST_MESH:
226 meshInfo = self._modelData[0]
227 self._modelData = self._modelData[1:]
228 sock.sendall(struct.pack('@i', meshInfo[0]))
229 sock.sendall(meshInfo[1].tostring())
230 elif cmd == self.GUI_CMD_SEND_POLYGONS:
231 cnt = struct.unpack('@i', sock.recv(4))[0]
232 layerNr = struct.unpack('@i', sock.recv(4))[0]
233 layerNr += layerNrOffset
234 z = struct.unpack('@i', sock.recv(4))[0]
235 z = float(z) / 1000.0
236 typeNameLen = struct.unpack('@i', sock.recv(4))[0]
237 typeName = sock.recv(typeNameLen)
238 while len(self._result._polygons) < layerNr + 1:
239 self._result._polygons.append({})
240 polygons = self._result._polygons[layerNr]
241 if typeName not in polygons:
242 polygons[typeName] = []
243 for n in xrange(0, cnt):
244 length = struct.unpack('@i', sock.recv(4))[0]
246 while len(data) < length * 8 * 2:
247 recvData = sock.recv(length * 8 * 2 - len(data))
248 if len(recvData) < 1:
251 polygon2d = numpy.array(numpy.fromstring(data, numpy.int64), numpy.float32) / 1000.0
252 polygon2d = polygon2d.reshape((len(polygon2d) / 2, 2))
253 polygon = numpy.empty((len(polygon2d), 3), numpy.float32)
254 polygon[:,:-1] = polygon2d
256 polygons[typeName].append(polygon)
257 elif cmd == self.GUI_CMD_FINISH_OBJECT:
258 layerNrOffset = len(self._result._polygons)
260 print "Unknown command on socket: %x" % (cmd)
264 self._serversocket.close()
266 def abortEngine(self):
267 if self._process is not None:
269 self._process.terminate()
272 if self._thread is not None:
277 if self._thread is not None:
283 def runEngine(self, scene):
284 if len(scene.objects()) < 1:
287 for obj in scene.objects():
288 if scene.checkPlatform(obj):
289 extruderCount = max(extruderCount, len(obj._meshList))
291 extruderCount = max(extruderCount, profile.minimalExtruderCount())
293 commandList = [getEngineFilename(), '-v', '-p']
294 for k, v in self._engineSettings(extruderCount).iteritems():
295 commandList += ['-s', '%s=%s' % (k, str(v))]
296 commandList += ['-g', '%d' % (self._serverPortNr)]
299 hash = hashlib.sha512()
300 order = scene.printOrder()
302 pos = numpy.array(profile.getMachineCenterCoords()) * 1000
305 for obj in scene.objects():
306 if scene.checkPlatform(obj):
307 oMin = obj.getMinimum()[0:2] + obj.getPosition()
308 oMax = obj.getMaximum()[0:2] + obj.getPosition()
313 objMin[0] = min(oMin[0], objMin[0])
314 objMin[1] = min(oMin[1], objMin[1])
315 objMax[0] = max(oMax[0], objMax[0])
316 objMax[1] = max(oMax[1], objMax[1])
319 pos += (objMin + objMax) / 2.0 * 1000
320 commandList += ['-s', 'posx=%d' % int(pos[0]), '-s', 'posy=%d' % int(pos[1])]
322 vertexTotal = [0] * 4
324 for obj in scene.objects():
325 if scene.checkPlatform(obj):
326 meshMax = max(meshMax, len(obj._meshList))
327 for n in xrange(0, len(obj._meshList)):
328 vertexTotal[n] += obj._meshList[n].vertexCount
330 for n in xrange(0, meshMax):
331 verts = numpy.zeros((0, 3), numpy.float32)
332 for obj in scene.objects():
333 if scene.checkPlatform(obj):
334 if n < len(obj._meshList):
335 vertexes = (numpy.matrix(obj._meshList[n].vertexes, copy = False) * numpy.matrix(obj._matrix, numpy.float32)).getA()
336 vertexes -= obj._drawOffset
337 vertexes += numpy.array([obj.getPosition()[0], obj.getPosition()[1], 0.0])
338 verts = numpy.concatenate((verts, vertexes))
339 hash.update(obj._meshList[n].vertexes.tostring())
340 engineModelData.append((vertexTotal[n], verts))
342 commandList += ['$' * meshMax]
346 obj = scene.objects()[n]
347 for mesh in obj._meshList:
348 engineModelData.append((mesh.vertexCount, mesh.vertexes))
349 hash.update(mesh.vertexes.tostring())
350 pos = obj.getPosition() * 1000
351 pos += numpy.array(profile.getMachineCenterCoords()) * 1000
352 commandList += ['-m', ','.join(map(str, obj._matrix.getA().flatten()))]
353 commandList += ['-s', 'posx=%d' % int(pos[0]), '-s', 'posy=%d' % int(pos[1])]
354 commandList += ['$' * len(obj._meshList)]
356 modelHash = hash.hexdigest()
357 if self._objCount > 0:
358 self._thread = threading.Thread(target=self._watchProcess, args=(commandList, self._thread, engineModelData, modelHash))
359 self._thread.daemon = True
362 def _watchProcess(self, commandList, oldThread, engineModelData, modelHash):
363 if oldThread is not None:
364 if self._process is not None:
365 self._process.terminate()
368 self._modelData = engineModelData
370 self._process = self._runEngineProcess(commandList)
372 traceback.print_exc()
374 if self._thread != threading.currentThread():
375 self._process.terminate()
377 self._result = EngineResult()
378 self._result.addLog('Running: %s' % (' '.join(commandList)))
379 self._result.setHash(modelHash)
382 logThread = threading.Thread(target=self._watchStderr, args=(self._process.stderr,))
383 logThread.daemon = True
386 data = self._process.stdout.read(4096)
388 self._result._gcodeData.write(data)
389 data = self._process.stdout.read(4096)
391 returnCode = self._process.wait()
394 pluginError = pluginInfo.runPostProcessingPlugins(self._result)
395 if pluginError is not None:
397 self._result.addLog(pluginError)
398 self._result.setFinished(True)
401 for line in self._result.getLog():
406 def _watchStderr(self, stderr):
408 line = stderr.readline()
411 if line.startswith('Progress:'):
412 line = line.split(':')
413 if line[1] == 'process':
415 elif line[1] in self._progressSteps:
416 progressValue = float(line[2]) / float(line[3])
417 progressValue /= len(self._progressSteps)
418 progressValue += 1.0 / len(self._progressSteps) * self._progressSteps.index(line[1])
420 progressValue /= self._objCount
421 progressValue += 1.0 / self._objCount * objectNr
423 self._callback(progressValue)
426 elif line.startswith('Print time:'):
427 self._result._printTimeSeconds = int(line.split(':')[1].strip())
428 elif line.startswith('Filament:'):
429 self._result._filamentMM[0] = int(line.split(':')[1].strip())
430 if profile.getMachineSetting('gcode_flavor') == 'UltiGCode':
431 radius = profile.getProfileSettingFloat('filament_diameter') / 2.0
432 self._result._filamentMM[0] /= (math.pi * radius * radius)
433 elif line.startswith('Filament2:'):
434 self._result._filamentMM[1] = int(line.split(':')[1].strip())
435 if profile.getMachineSetting('gcode_flavor') == 'UltiGCode':
436 radius = profile.getProfileSettingFloat('filament_diameter') / 2.0
437 self._result._filamentMM[1] /= (math.pi * radius * radius)
438 elif line.startswith('Replace:'):
439 self._result._replaceInfo[line.split(':')[1].strip()] = line.split(':')[2].strip()
441 self._result.addLog(line)
442 line = stderr.readline()
444 def _engineSettings(self, extruderCount):
446 'layerThickness': int(profile.getProfileSettingFloat('layer_height') * 1000),
447 'initialLayerThickness': int(profile.getProfileSettingFloat('bottom_thickness') * 1000) if profile.getProfileSettingFloat('bottom_thickness') > 0.0 else int(profile.getProfileSettingFloat('layer_height') * 1000),
448 'filamentDiameter': int(profile.getProfileSettingFloat('filament_diameter') * 1000),
449 'filamentFlow': int(profile.getProfileSettingFloat('filament_flow')),
450 'extrusionWidth': int(profile.calculateEdgeWidth() * 1000),
451 'layer0extrusionWidth': int(profile.calculateEdgeWidth() * profile.getProfileSettingFloat('layer0_width_factor') / 100 * 1000),
452 'insetCount': int(profile.calculateLineCount()),
453 'downSkinCount': int(profile.calculateSolidLayerCount()) if profile.getProfileSetting('solid_bottom') == 'True' else 0,
454 'upSkinCount': int(profile.calculateSolidLayerCount()) if profile.getProfileSetting('solid_top') == 'True' else 0,
455 'infillOverlap': int(profile.getProfileSettingFloat('fill_overlap')),
456 'initialSpeedupLayers': int(4),
457 'initialLayerSpeed': int(profile.getProfileSettingFloat('bottom_layer_speed')),
458 'printSpeed': int(profile.getProfileSettingFloat('print_speed')),
459 'infillSpeed': int(profile.getProfileSettingFloat('infill_speed')) if int(profile.getProfileSettingFloat('infill_speed')) > 0 else int(profile.getProfileSettingFloat('print_speed')),
460 'inset0Speed': int(profile.getProfileSettingFloat('inset0_speed')) if int(profile.getProfileSettingFloat('inset0_speed')) > 0 else int(profile.getProfileSettingFloat('print_speed')),
461 'insetXSpeed': int(profile.getProfileSettingFloat('insetx_speed')) if int(profile.getProfileSettingFloat('insetx_speed')) > 0 else int(profile.getProfileSettingFloat('print_speed')),
462 'moveSpeed': int(profile.getProfileSettingFloat('travel_speed')),
463 'fanSpeedMin': int(profile.getProfileSettingFloat('fan_speed')) if profile.getProfileSetting('fan_enabled') == 'True' else 0,
464 'fanSpeedMax': int(profile.getProfileSettingFloat('fan_speed_max')) if profile.getProfileSetting('fan_enabled') == 'True' else 0,
465 'supportAngle': int(-1) if profile.getProfileSetting('support') == 'None' else int(profile.getProfileSettingFloat('support_angle')),
466 'supportEverywhere': int(1) if profile.getProfileSetting('support') == 'Everywhere' else int(0),
467 'supportLineDistance': int(100 * profile.calculateEdgeWidth() * 1000 / profile.getProfileSettingFloat('support_fill_rate')) if profile.getProfileSettingFloat('support_fill_rate') > 0 else -1,
468 'supportXYDistance': int(1000 * profile.getProfileSettingFloat('support_xy_distance')),
469 'supportZDistance': int(1000 * profile.getProfileSettingFloat('support_z_distance')),
470 '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),
471 'retractionAmount': int(profile.getProfileSettingFloat('retraction_amount') * 1000) if profile.getProfileSetting('retraction_enable') == 'True' else 0,
472 'retractionSpeed': int(profile.getProfileSettingFloat('retraction_speed')),
473 'retractionMinimalDistance': int(profile.getProfileSettingFloat('retraction_min_travel') * 1000),
474 'retractionAmountExtruderSwitch': int(profile.getProfileSettingFloat('retraction_dual_amount') * 1000),
475 'retractionZHop': int(profile.getProfileSettingFloat('retraction_hop') * 1000),
476 'minimalExtrusionBeforeRetraction': int(profile.getProfileSettingFloat('retraction_minimal_extrusion') * 1000),
477 'enableCombing': 1 if profile.getProfileSetting('retraction_combing') == 'True' else 0,
478 'multiVolumeOverlap': int(profile.getProfileSettingFloat('overlap_dual') * 1000),
479 'objectSink': max(0, int(profile.getProfileSettingFloat('object_sink') * 1000)),
480 'minimalLayerTime': int(profile.getProfileSettingFloat('cool_min_layer_time')),
481 'minimalFeedrate': int(profile.getProfileSettingFloat('cool_min_feedrate')),
482 'coolHeadLift': 1 if profile.getProfileSetting('cool_head_lift') == 'True' else 0,
483 'startCode': profile.getAlterationFileContents('start.gcode', extruderCount),
484 'endCode': profile.getAlterationFileContents('end.gcode', extruderCount),
485 'preSwitchExtruderCode': profile.getAlterationFileContents('preSwitchExtruder.gcode', extruderCount),
486 'postSwitchExtruderCode': profile.getAlterationFileContents('postSwitchExtruder.gcode', extruderCount),
488 'extruderOffset[1].X': int(profile.getMachineSettingFloat('extruder_offset_x1') * 1000),
489 'extruderOffset[1].Y': int(profile.getMachineSettingFloat('extruder_offset_y1') * 1000),
490 'extruderOffset[2].X': int(profile.getMachineSettingFloat('extruder_offset_x2') * 1000),
491 'extruderOffset[2].Y': int(profile.getMachineSettingFloat('extruder_offset_y2') * 1000),
492 'extruderOffset[3].X': int(profile.getMachineSettingFloat('extruder_offset_x3') * 1000),
493 'extruderOffset[3].Y': int(profile.getMachineSettingFloat('extruder_offset_y3') * 1000),
496 fanFullHeight = int(profile.getProfileSettingFloat('fan_full_height') * 1000)
497 settings['fanFullOnLayerNr'] = (fanFullHeight - settings['initialLayerThickness'] - 1) / settings['layerThickness'] + 1
498 if settings['fanFullOnLayerNr'] < 0:
499 settings['fanFullOnLayerNr'] = 0
500 if profile.getProfileSetting('support_type') == 'Lines':
501 settings['supportType'] = 1
503 if profile.getProfileSettingFloat('fill_density') == 0:
504 settings['sparseInfillLineDistance'] = -1
505 elif profile.getProfileSettingFloat('fill_density') == 100:
506 settings['sparseInfillLineDistance'] = settings['extrusionWidth']
507 #Set the up/down skins height to 10000 if we want a 100% filled object.
508 # This gives better results then normal 100% infill as the sparse and up/down skin have some overlap.
509 settings['downSkinCount'] = 10000
510 settings['upSkinCount'] = 10000
512 settings['sparseInfillLineDistance'] = int(100 * profile.calculateEdgeWidth() * 1000 / profile.getProfileSettingFloat('fill_density'))
513 if profile.getProfileSetting('platform_adhesion') == 'Brim':
514 settings['skirtDistance'] = 0
515 settings['skirtLineCount'] = int(profile.getProfileSettingFloat('brim_line_count'))
516 elif profile.getProfileSetting('platform_adhesion') == 'Raft':
517 settings['skirtDistance'] = 0
518 settings['skirtLineCount'] = 0
519 settings['raftMargin'] = int(profile.getProfileSettingFloat('raft_margin') * 1000)
520 settings['raftLineSpacing'] = int(profile.getProfileSettingFloat('raft_line_spacing') * 1000)
521 settings['raftBaseThickness'] = int(profile.getProfileSettingFloat('raft_base_thickness') * 1000)
522 settings['raftBaseLinewidth'] = int(profile.getProfileSettingFloat('raft_base_linewidth') * 1000)
523 settings['raftInterfaceThickness'] = int(profile.getProfileSettingFloat('raft_interface_thickness') * 1000)
524 settings['raftInterfaceLinewidth'] = int(profile.getProfileSettingFloat('raft_interface_linewidth') * 1000)
525 settings['raftInterfaceLineSpacing'] = int(profile.getProfileSettingFloat('raft_interface_linewidth') * 1000 * 2.0)
526 settings['raftAirGapLayer0'] = int(profile.getProfileSettingFloat('raft_airgap') * 1000)
527 settings['raftBaseSpeed'] = int(profile.getProfileSettingFloat('bottom_layer_speed'))
528 settings['raftFanSpeed'] = 100
529 settings['raftSurfaceThickness'] = settings['raftInterfaceThickness']
530 settings['raftSurfaceLinewidth'] = int(profile.calculateEdgeWidth() * 1000)
531 settings['raftSurfaceLineSpacing'] = int(profile.calculateEdgeWidth() * 1000 * 0.9)
532 settings['raftSurfaceLayers'] = int(profile.getProfileSettingFloat('raft_surface_layers'))
533 settings['raftSurfaceSpeed'] = int(profile.getProfileSettingFloat('bottom_layer_speed'))
535 settings['skirtDistance'] = int(profile.getProfileSettingFloat('skirt_gap') * 1000)
536 settings['skirtLineCount'] = int(profile.getProfileSettingFloat('skirt_line_count'))
537 settings['skirtMinLength'] = int(profile.getProfileSettingFloat('skirt_minimal_length') * 1000)
539 if profile.getProfileSetting('fix_horrible_union_all_type_a') == 'True':
540 settings['fixHorrible'] |= 0x01
541 if profile.getProfileSetting('fix_horrible_union_all_type_b') == 'True':
542 settings['fixHorrible'] |= 0x02
543 if profile.getProfileSetting('fix_horrible_use_open_bits') == 'True':
544 settings['fixHorrible'] |= 0x10
545 if profile.getProfileSetting('fix_horrible_extensive_stitching') == 'True':
546 settings['fixHorrible'] |= 0x04
548 if settings['layerThickness'] <= 0:
549 settings['layerThickness'] = 1000
550 if profile.getMachineSetting('gcode_flavor') == 'UltiGCode':
551 settings['gcodeFlavor'] = 1
552 elif profile.getMachineSetting('gcode_flavor') == 'MakerBot':
553 settings['gcodeFlavor'] = 2
554 elif profile.getMachineSetting('gcode_flavor') == 'BFB':
555 settings['gcodeFlavor'] = 3
556 elif profile.getMachineSetting('gcode_flavor') == 'Mach3':
557 settings['gcodeFlavor'] = 4
558 elif profile.getMachineSetting('gcode_flavor') == 'RepRap (Volumetric)':
559 settings['gcodeFlavor'] = 5
560 if profile.getProfileSetting('spiralize') == 'True':
561 settings['spiralizeMode'] = 1
562 if profile.getProfileSetting('simple_mode') == 'True':
563 settings['simpleMode'] = 1
564 if profile.getProfileSetting('wipe_tower') == 'True' and extruderCount > 1:
565 settings['wipeTowerSize'] = int(math.sqrt(profile.getProfileSettingFloat('wipe_tower_volume') * 1000 * 1000 * 1000 / settings['layerThickness']))
566 if profile.getProfileSetting('ooze_shield') == 'True':
567 settings['enableOozeShield'] = 1
570 def _runEngineProcess(self, cmdList):
572 if subprocess.mswindows:
573 su = subprocess.STARTUPINFO()
574 su.dwFlags |= subprocess.STARTF_USESHOWWINDOW
575 su.wShowWindow = subprocess.SW_HIDE
576 kwargs['startupinfo'] = su
577 kwargs['creationflags'] = 0x00004000 #BELOW_NORMAL_PRIORITY_CLASS
578 return subprocess.Popen(cmdList, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs)