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 from Cura.util.bigDataStorage import BigDataStorage
23 from Cura.util import profile
24 from Cura.util import pluginInfo
25 from Cura.util import version
26 from Cura.util import gcodeInterpreter
28 def getEngineFilename():
30 Finds and returns the path to the current engine executable. This is OS depended.
31 :return: The full path to the engine executable.
33 base_search_path = os.path.dirname(inspect.getfile(getEngineFilename))
34 search_filename = 'CuraEngine'
35 if platform.system() == 'Windows':
36 search_filename += '.exe'
37 if version.isDevVersion() and os.path.exists('C:/Software/Cura_SteamEngine/_bin/Release/Cura_SteamEngine.exe'):
38 return 'C:/Software/Cura_SteamEngine/_bin/Release/Cura_SteamEngine.exe'
39 for n in xrange(0, 10):
40 full_filename = os.path.abspath(os.path.join(base_search_path, '/'.join(['..'] * n), search_filename))
41 if os.path.isfile(full_filename):
43 full_filename = os.path.abspath(os.path.join(base_search_path, '/'.join(['..'] * n), 'CuraEngine', search_filename))
44 if os.path.isfile(full_filename):
46 if os.path.isfile('/usr/bin/CuraEngine'):
47 return '/usr/bin/CuraEngine'
48 if os.path.isfile('/usr/local/bin/CuraEngine'):
49 return '/usr/local/bin/CuraEngine'
52 class EngineResult(object):
54 Result from running the CuraEngine.
55 Contains the engine log, polygons retrieved from the engine, the GCode and some meta-data.
59 self._gcodeData = BigDataStorage()
61 self._replaceInfo = {}
63 self._printTimeSeconds = None
64 self._filamentMM = [0.0] * 4
65 self._modelHash = None
66 self._profileString = profile.getProfileString()
67 self._preferencesString = profile.getPreferencesString()
68 self._gcodeInterpreter = gcodeInterpreter.gcode()
69 self._gcodeLoadThread = None
70 self._finished = False
72 def getFilamentWeight(self, e=0):
73 #Calculates the weight of the filament in kg
74 radius = float(profile.getProfileSetting('filament_diameter')) / 2
75 volumeM3 = (self._filamentMM[e] * (math.pi * radius * radius)) / (1000*1000*1000)
76 return volumeM3 * profile.getPreferenceFloat('filament_physical_density')
78 def getFilamentCost(self, e=0):
79 cost_kg = profile.getPreferenceFloat('filament_cost_kg')
80 cost_meter = profile.getPreferenceFloat('filament_cost_meter')
81 if cost_kg > 0.0 and cost_meter > 0.0:
82 return "%.2f / %.2f" % (self.getFilamentWeight(e) * cost_kg, self._filamentMM[e] / 1000.0 * cost_meter)
84 return "%.2f" % (self.getFilamentWeight(e) * cost_kg)
85 elif cost_meter > 0.0:
86 return "%.2f" % (self._filamentMM[e] / 1000.0 * cost_meter)
89 def getPrintTime(self):
90 if self._printTimeSeconds is None:
92 if int(self._printTimeSeconds / 60 / 60) < 1:
93 return _('%d minutes') % (int(self._printTimeSeconds / 60) % 60)
94 if int(self._printTimeSeconds / 60 / 60) == 1:
95 return _('%d hour %d minutes') % (int(self._printTimeSeconds / 60 / 60), int(self._printTimeSeconds / 60) % 60)
96 return _('%d hours %d minutes') % (int(self._printTimeSeconds / 60 / 60), int(self._printTimeSeconds / 60) % 60)
98 def getFilamentAmount(self, e=0):
99 if self._filamentMM[e] == 0.0:
101 return _('%0.2f meter %0.0f gram') % (float(self._filamentMM[e]) / 1000.0, self.getFilamentWeight(e) * 1000.0)
104 return self._engineLog
107 self._gcodeData.seekStart()
108 return self._gcodeData
110 def setGCode(self, gcode):
111 self._gcodeData = BigDataStorage()
112 self._gcodeData.write(gcode)
113 self._replaceInfo = {}
115 def addLog(self, line):
116 self._engineLog.append(line)
118 def setHash(self, hash):
119 self._modelHash = hash
121 def setFinished(self, result):
123 for k, v in self._replaceInfo.items():
124 self._gcodeData.replaceAtStart(k, v)
125 self._finished = result
127 def isFinished(self):
128 return self._finished
130 def getGCodeLayers(self, loadCallback):
131 if not self._finished:
133 if self._gcodeInterpreter.layerList is None and self._gcodeLoadThread is None:
134 self._gcodeInterpreter.progressCallback = self._gcodeInterpreterCallback
135 self._gcodeLoadThread = threading.Thread(target=lambda : self._gcodeInterpreter.load(self._gcodeData.clone()))
136 self._gcodeLoadCallback = loadCallback
137 self._gcodeLoadThread.daemon = True
138 self._gcodeLoadThread.start()
139 return self._gcodeInterpreter.layerList
141 def _gcodeInterpreterCallback(self, progress):
142 if len(self._gcodeInterpreter.layerList) % 5 == 0:
144 return self._gcodeLoadCallback(self, progress)
146 def submitInfoOnline(self):
147 if profile.getPreference('submit_slice_information') != 'True':
149 if version.isDevVersion():
152 'processor': platform.processor(),
153 'machine': platform.machine(),
154 'platform': platform.platform(),
155 'profile': self._profileString,
156 'preferences': self._preferencesString,
157 'modelhash': self._modelHash,
158 'version': version.getVersion(),
161 f = urllib2.urlopen("https://www.youmagine.com/curastats/", data = urllib.urlencode(data), timeout = 1)
166 traceback.print_exc()
168 class Engine(object):
170 Class used to communicate with the CuraEngine.
171 The CuraEngine is ran as a 2nd process and reports back information trough stderr.
172 GCode trough stdout and has a socket connection for polygon information and loading the 3D model into the engine.
174 GUI_CMD_REQUEST_MESH = 0x01
175 GUI_CMD_SEND_POLYGONS = 0x02
176 GUI_CMD_FINISH_OBJECT = 0x03
178 def __init__(self, progressCallback):
181 self._callback = progressCallback
182 self._progressSteps = ['inset', 'skin', 'export']
186 self._engine_executable = getEngineFilename()
187 self._serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
188 self._serverPortNr = 0xC20A
189 for potential_port in xrange(0xC20A, 0xFFFF):
190 self._serverPortNr = potential_port
192 self._serversocket.bind(('127.0.0.1', self._serverPortNr))
195 print("Failed to listen on port: %d" % (self._serverPortNr))
197 print("Failed to listen on any port, this is a fatal error")
199 thread = threading.Thread(target=self._socketListenThread)
203 def _socketListenThread(self):
204 self._serversocket.listen(1)
205 print 'Listening for engine communications on %d' % (self._serverPortNr)
208 sock, _ = self._serversocket.accept()
209 thread = threading.Thread(target=self._socketConnectionThread, args=(sock,))
212 except socket.error, e:
213 if e.errno != errno.EINTR:
216 def _socketConnectionThread(self, sock):
226 cmd = struct.unpack('@i', data)[0]
227 if cmd == self.GUI_CMD_REQUEST_MESH:
228 meshInfo = self._modelData[0]
229 self._modelData = self._modelData[1:]
230 sock.sendall(struct.pack('@i', meshInfo[0]))
231 sock.sendall(meshInfo[1].tostring())
232 elif cmd == self.GUI_CMD_SEND_POLYGONS:
233 cnt = struct.unpack('@i', sock.recv(4))[0]
234 layerNr = struct.unpack('@i', sock.recv(4))[0]
235 layerNr += layerNrOffset
236 z = struct.unpack('@i', sock.recv(4))[0]
237 z = float(z) / 1000.0
238 typeNameLen = struct.unpack('@i', sock.recv(4))[0]
239 typeName = sock.recv(typeNameLen)
240 while len(self._result._polygons) < layerNr + 1:
241 self._result._polygons.append({})
242 polygons = self._result._polygons[layerNr]
243 if typeName not in polygons:
244 polygons[typeName] = []
245 for n in xrange(0, cnt):
246 length = struct.unpack('@i', sock.recv(4))[0]
248 while len(data) < length * 8 * 2:
249 recvData = sock.recv(length * 8 * 2 - len(data))
250 if len(recvData) < 1:
253 polygon2d = numpy.array(numpy.fromstring(data, numpy.int64), numpy.float32) / 1000.0
254 polygon2d = polygon2d.reshape((len(polygon2d) / 2, 2))
255 polygon = numpy.empty((len(polygon2d), 3), numpy.float32)
256 polygon[:,:-1] = polygon2d
258 polygons[typeName].append(polygon)
259 elif cmd == self.GUI_CMD_FINISH_OBJECT:
260 layerNrOffset = len(self._result._polygons)
262 print "Unknown command on socket: %x" % (cmd)
266 self._serversocket.close()
268 def abortEngine(self):
269 if self._process is not None:
271 self._process.terminate()
274 if self._thread is not None:
279 if self._thread is not None:
285 def runEngine(self, scene):
286 if len(scene.objects()) < 1:
289 for obj in scene.objects():
290 if scene.checkPlatform(obj):
291 extruderCount = max(extruderCount, len(obj._meshList))
293 extruderCount = max(extruderCount, profile.minimalExtruderCount())
295 commandList = [self._engine_executable, '-v', '-p']
296 for k, v in self._engineSettings(extruderCount).iteritems():
297 commandList += ['-s', '%s=%s' % (k, str(v))]
298 commandList += ['-g', '%d' % (self._serverPortNr)]
301 hash = hashlib.sha512()
302 order = scene.printOrder()
304 pos = numpy.array(profile.getMachineCenterCoords()) * 1000
307 for obj in scene.objects():
308 if scene.checkPlatform(obj):
309 oMin = obj.getMinimum()[0:2] + obj.getPosition()
310 oMax = obj.getMaximum()[0:2] + obj.getPosition()
315 objMin[0] = min(oMin[0], objMin[0])
316 objMin[1] = min(oMin[1], objMin[1])
317 objMax[0] = max(oMax[0], objMax[0])
318 objMax[1] = max(oMax[1], objMax[1])
321 pos += (objMin + objMax) / 2.0 * 1000
322 commandList += ['-s', 'posx=%d' % int(pos[0]), '-s', 'posy=%d' % int(pos[1])]
324 vertexTotal = [0] * 4
326 for obj in scene.objects():
327 if scene.checkPlatform(obj):
328 meshMax = max(meshMax, len(obj._meshList))
329 for n in xrange(0, len(obj._meshList)):
330 vertexTotal[n] += obj._meshList[n].vertexCount
332 for n in xrange(0, meshMax):
333 verts = numpy.zeros((0, 3), numpy.float32)
334 for obj in scene.objects():
335 if scene.checkPlatform(obj):
336 if n < len(obj._meshList):
337 vertexes = (numpy.matrix(obj._meshList[n].vertexes, copy = False) * numpy.matrix(obj._matrix, numpy.float32)).getA()
338 vertexes -= obj._drawOffset
339 vertexes += numpy.array([obj.getPosition()[0], obj.getPosition()[1], 0.0])
340 verts = numpy.concatenate((verts, vertexes))
341 hash.update(obj._meshList[n].vertexes.tostring())
342 engineModelData.append((vertexTotal[n], verts))
344 commandList += ['$' * meshMax]
348 obj = scene.objects()[n]
349 for mesh in obj._meshList:
350 engineModelData.append((mesh.vertexCount, mesh.vertexes))
351 hash.update(mesh.vertexes.tostring())
352 pos = obj.getPosition() * 1000
353 pos += numpy.array(profile.getMachineCenterCoords()) * 1000
354 commandList += ['-m', ','.join(map(str, obj._matrix.getA().flatten()))]
355 commandList += ['-s', 'posx=%d' % int(pos[0]), '-s', 'posy=%d' % int(pos[1])]
356 commandList += ['$' * len(obj._meshList)]
358 modelHash = hash.hexdigest()
359 if self._objCount > 0:
360 self._thread = threading.Thread(target=self._watchProcess, args=(commandList, self._thread, engineModelData, modelHash))
361 self._thread.daemon = True
364 def _watchProcess(self, commandList, oldThread, engineModelData, modelHash):
365 if oldThread is not None:
366 if self._process is not None:
367 self._process.terminate()
370 self._modelData = engineModelData
372 self._process = self._runEngineProcess(commandList)
374 traceback.print_exc()
376 if self._thread != threading.currentThread():
377 self._process.terminate()
379 self._result = EngineResult()
380 self._result.addLog('Running: %s' % (' '.join(commandList)))
381 self._result.setHash(modelHash)
384 logThread = threading.Thread(target=self._watchStderr, args=(self._process.stderr,))
385 logThread.daemon = True
388 data = self._process.stdout.read(4096)
390 self._result._gcodeData.write(data)
391 data = self._process.stdout.read(4096)
393 returnCode = self._process.wait()
396 pluginError = pluginInfo.runPostProcessingPlugins(self._result)
397 if pluginError is not None:
399 self._result.addLog(pluginError)
400 self._result.setFinished(True)
403 for line in self._result.getLog():
408 def _watchStderr(self, stderr):
410 line = stderr.readline()
413 if line.startswith('Progress:'):
414 line = line.split(':')
415 if line[1] == 'process':
417 elif line[1] in self._progressSteps:
418 progressValue = float(line[2]) / float(line[3])
419 progressValue /= len(self._progressSteps)
420 progressValue += 1.0 / len(self._progressSteps) * self._progressSteps.index(line[1])
422 progressValue /= self._objCount
423 progressValue += 1.0 / self._objCount * objectNr
425 self._callback(progressValue)
428 elif line.startswith('Print time:'):
429 self._result._printTimeSeconds = int(line.split(':')[1].strip())
430 elif line.startswith('Filament:'):
431 self._result._filamentMM[0] = int(line.split(':')[1].strip())
432 if profile.getMachineSetting('gcode_flavor') == 'UltiGCode':
433 radius = profile.getProfileSettingFloat('filament_diameter') / 2.0
434 self._result._filamentMM[0] /= (math.pi * radius * radius)
435 elif line.startswith('Filament2:'):
436 self._result._filamentMM[1] = int(line.split(':')[1].strip())
437 if profile.getMachineSetting('gcode_flavor') == 'UltiGCode':
438 radius = profile.getProfileSettingFloat('filament_diameter') / 2.0
439 self._result._filamentMM[1] /= (math.pi * radius * radius)
440 elif line.startswith('Replace:'):
441 self._result._replaceInfo[line.split(':')[1].strip()] = line.split(':')[2].strip()
443 self._result.addLog(line)
444 line = stderr.readline()
446 def _engineSettings(self, extruderCount):
448 'layerThickness': int(profile.getProfileSettingFloat('layer_height') * 1000),
449 'initialLayerThickness': int(profile.getProfileSettingFloat('bottom_thickness') * 1000) if profile.getProfileSettingFloat('bottom_thickness') > 0.0 else int(profile.getProfileSettingFloat('layer_height') * 1000),
450 'filamentDiameter': int(profile.getProfileSettingFloat('filament_diameter') * 1000),
451 'filamentFlow': int(profile.getProfileSettingFloat('filament_flow')),
452 'extrusionWidth': int(profile.calculateEdgeWidth() * 1000),
453 'layer0extrusionWidth': int(profile.calculateEdgeWidth() * profile.getProfileSettingFloat('layer0_width_factor') / 100 * 1000),
454 'insetCount': int(profile.calculateLineCount()),
455 'downSkinCount': int(profile.calculateSolidLayerCount()) if profile.getProfileSetting('solid_bottom') == 'True' else 0,
456 'upSkinCount': int(profile.calculateSolidLayerCount()) if profile.getProfileSetting('solid_top') == 'True' else 0,
457 'infillOverlap': int(profile.getProfileSettingFloat('fill_overlap')),
458 'initialSpeedupLayers': int(4),
459 'initialLayerSpeed': int(profile.getProfileSettingFloat('bottom_layer_speed')),
460 'printSpeed': int(profile.getProfileSettingFloat('print_speed')),
461 'infillSpeed': int(profile.getProfileSettingFloat('infill_speed')) if int(profile.getProfileSettingFloat('infill_speed')) > 0 else int(profile.getProfileSettingFloat('print_speed')),
462 'inset0Speed': int(profile.getProfileSettingFloat('inset0_speed')) if int(profile.getProfileSettingFloat('inset0_speed')) > 0 else int(profile.getProfileSettingFloat('print_speed')),
463 'insetXSpeed': int(profile.getProfileSettingFloat('insetx_speed')) if int(profile.getProfileSettingFloat('insetx_speed')) > 0 else int(profile.getProfileSettingFloat('print_speed')),
464 'moveSpeed': int(profile.getProfileSettingFloat('travel_speed')),
465 'fanSpeedMin': int(profile.getProfileSettingFloat('fan_speed')) if profile.getProfileSetting('fan_enabled') == 'True' else 0,
466 'fanSpeedMax': int(profile.getProfileSettingFloat('fan_speed_max')) if profile.getProfileSetting('fan_enabled') == 'True' else 0,
467 'supportAngle': int(-1) if profile.getProfileSetting('support') == 'None' else int(profile.getProfileSettingFloat('support_angle')),
468 'supportEverywhere': int(1) if profile.getProfileSetting('support') == 'Everywhere' else int(0),
469 'supportLineDistance': int(100 * profile.calculateEdgeWidth() * 1000 / profile.getProfileSettingFloat('support_fill_rate')) if profile.getProfileSettingFloat('support_fill_rate') > 0 else -1,
470 'supportXYDistance': int(1000 * profile.getProfileSettingFloat('support_xy_distance')),
471 'supportZDistance': int(1000 * profile.getProfileSettingFloat('support_z_distance')),
472 '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),
473 'retractionAmount': int(profile.getProfileSettingFloat('retraction_amount') * 1000) if profile.getProfileSetting('retraction_enable') == 'True' else 0,
474 'retractionSpeed': int(profile.getProfileSettingFloat('retraction_speed')),
475 'retractionMinimalDistance': int(profile.getProfileSettingFloat('retraction_min_travel') * 1000),
476 'retractionAmountExtruderSwitch': int(profile.getProfileSettingFloat('retraction_dual_amount') * 1000),
477 'retractionZHop': int(profile.getProfileSettingFloat('retraction_hop') * 1000),
478 'minimalExtrusionBeforeRetraction': int(profile.getProfileSettingFloat('retraction_minimal_extrusion') * 1000),
479 'enableCombing': 1 if profile.getProfileSetting('retraction_combing') == 'True' else 0,
480 'multiVolumeOverlap': int(profile.getProfileSettingFloat('overlap_dual') * 1000),
481 'objectSink': max(0, int(profile.getProfileSettingFloat('object_sink') * 1000)),
482 'minimalLayerTime': int(profile.getProfileSettingFloat('cool_min_layer_time')),
483 'minimalFeedrate': int(profile.getProfileSettingFloat('cool_min_feedrate')),
484 'coolHeadLift': 1 if profile.getProfileSetting('cool_head_lift') == 'True' else 0,
485 'startCode': profile.getAlterationFileContents('start.gcode', extruderCount),
486 'endCode': profile.getAlterationFileContents('end.gcode', extruderCount),
487 'preSwitchExtruderCode': profile.getAlterationFileContents('preSwitchExtruder.gcode', extruderCount),
488 'postSwitchExtruderCode': profile.getAlterationFileContents('postSwitchExtruder.gcode', extruderCount),
490 'extruderOffset[1].X': int(profile.getMachineSettingFloat('extruder_offset_x1') * 1000),
491 'extruderOffset[1].Y': int(profile.getMachineSettingFloat('extruder_offset_y1') * 1000),
492 'extruderOffset[2].X': int(profile.getMachineSettingFloat('extruder_offset_x2') * 1000),
493 'extruderOffset[2].Y': int(profile.getMachineSettingFloat('extruder_offset_y2') * 1000),
494 'extruderOffset[3].X': int(profile.getMachineSettingFloat('extruder_offset_x3') * 1000),
495 'extruderOffset[3].Y': int(profile.getMachineSettingFloat('extruder_offset_y3') * 1000),
498 fanFullHeight = int(profile.getProfileSettingFloat('fan_full_height') * 1000)
499 settings['fanFullOnLayerNr'] = (fanFullHeight - settings['initialLayerThickness'] - 1) / settings['layerThickness'] + 1
500 if settings['fanFullOnLayerNr'] < 0:
501 settings['fanFullOnLayerNr'] = 0
502 if profile.getProfileSetting('support_type') == 'Lines':
503 settings['supportType'] = 1
505 if profile.getProfileSettingFloat('fill_density') == 0:
506 settings['sparseInfillLineDistance'] = -1
507 elif profile.getProfileSettingFloat('fill_density') == 100:
508 settings['sparseInfillLineDistance'] = settings['extrusionWidth']
509 #Set the up/down skins height to 10000 if we want a 100% filled object.
510 # This gives better results then normal 100% infill as the sparse and up/down skin have some overlap.
511 settings['downSkinCount'] = 10000
512 settings['upSkinCount'] = 10000
514 settings['sparseInfillLineDistance'] = int(100 * profile.calculateEdgeWidth() * 1000 / profile.getProfileSettingFloat('fill_density'))
515 if profile.getProfileSetting('platform_adhesion') == 'Brim':
516 settings['skirtDistance'] = 0
517 settings['skirtLineCount'] = int(profile.getProfileSettingFloat('brim_line_count'))
518 elif profile.getProfileSetting('platform_adhesion') == 'Raft':
519 settings['skirtDistance'] = 0
520 settings['skirtLineCount'] = 0
521 settings['raftMargin'] = int(profile.getProfileSettingFloat('raft_margin') * 1000)
522 settings['raftLineSpacing'] = int(profile.getProfileSettingFloat('raft_line_spacing') * 1000)
523 settings['raftBaseThickness'] = int(profile.getProfileSettingFloat('raft_base_thickness') * 1000)
524 settings['raftBaseLinewidth'] = int(profile.getProfileSettingFloat('raft_base_linewidth') * 1000)
525 settings['raftInterfaceThickness'] = int(profile.getProfileSettingFloat('raft_interface_thickness') * 1000)
526 settings['raftInterfaceLinewidth'] = int(profile.getProfileSettingFloat('raft_interface_linewidth') * 1000)
527 settings['raftInterfaceLineSpacing'] = int(profile.getProfileSettingFloat('raft_interface_linewidth') * 1000 * 2.0)
528 settings['raftAirGapLayer0'] = int(profile.getProfileSettingFloat('raft_airgap') * 1000 + profile.getProfileSettingFloat('raft_airgap_all') * 1000)
529 settings['raftAirGap'] = int(profile.getProfileSettingFloat('raft_airgap_all') * 1000)
530 settings['raftBaseSpeed'] = int(profile.getProfileSettingFloat('bottom_layer_speed'))
531 settings['raftFanSpeed'] = 0
532 settings['raftSurfaceThickness'] = int(profile.getProfileSettingFloat('raft_surface_thickness') * 1000)
533 settings['raftSurfaceLinewidth'] = int(profile.getProfileSettingFloat('raft_surface_linewidth') * 1000)
534 settings['raftSurfaceLineSpacing'] = int(profile.getProfileSettingFloat('raft_surface_linewidth') * 1000)
535 settings['raftSurfaceLayers'] = int(profile.getProfileSettingFloat('raft_surface_layers'))
536 settings['raftSurfaceSpeed'] = int(profile.getProfileSettingFloat('bottom_layer_speed'))
538 settings['skirtDistance'] = int(profile.getProfileSettingFloat('skirt_gap') * 1000)
539 settings['skirtLineCount'] = int(profile.getProfileSettingFloat('skirt_line_count'))
540 settings['skirtMinLength'] = int(profile.getProfileSettingFloat('skirt_minimal_length') * 1000)
542 if profile.getProfileSetting('fix_horrible_union_all_type_a') == 'True':
543 settings['fixHorrible'] |= 0x01
544 if profile.getProfileSetting('fix_horrible_union_all_type_b') == 'True':
545 settings['fixHorrible'] |= 0x02
546 if profile.getProfileSetting('fix_horrible_use_open_bits') == 'True':
547 settings['fixHorrible'] |= 0x10
548 if profile.getProfileSetting('fix_horrible_extensive_stitching') == 'True':
549 settings['fixHorrible'] |= 0x04
551 if settings['layerThickness'] <= 0:
552 settings['layerThickness'] = 1000
553 if profile.getMachineSetting('gcode_flavor') == 'UltiGCode':
554 settings['gcodeFlavor'] = 1
555 elif profile.getMachineSetting('gcode_flavor') == 'MakerBot':
556 settings['gcodeFlavor'] = 2
557 elif profile.getMachineSetting('gcode_flavor') == 'BFB':
558 settings['gcodeFlavor'] = 3
559 elif profile.getMachineSetting('gcode_flavor') == 'Mach3':
560 settings['gcodeFlavor'] = 4
561 elif profile.getMachineSetting('gcode_flavor') == 'RepRap (Volumetric)':
562 settings['gcodeFlavor'] = 5
563 if profile.getProfileSetting('spiralize') == 'True':
564 settings['spiralizeMode'] = 1
565 if profile.getProfileSetting('simple_mode') == 'True':
566 settings['simpleMode'] = 1
567 if profile.getProfileSetting('wipe_tower') == 'True' and extruderCount > 1:
568 settings['wipeTowerSize'] = int(math.sqrt(profile.getProfileSettingFloat('wipe_tower_volume') * 1000 * 1000 * 1000 / settings['layerThickness']))
569 if profile.getProfileSetting('ooze_shield') == 'True':
570 settings['enableOozeShield'] = 1
573 def _runEngineProcess(self, cmdList):
575 if subprocess.mswindows:
576 su = subprocess.STARTUPINFO()
577 su.dwFlags |= subprocess.STARTF_USESHOWWINDOW
578 su.wShowWindow = subprocess.SW_HIDE
579 kwargs['startupinfo'] = su
580 kwargs['creationflags'] = 0x00004000 #BELOW_NORMAL_PRIORITY_CLASS
581 return subprocess.Popen(cmdList, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs)