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(),
159 'printtime': self._printTimeSeconds,
160 'filament': ','.join(map(str, self._filamentMM)),
163 f = urllib2.urlopen("https://stats.youmagine.com/curastats/slice", data = urllib.urlencode(data), timeout = 1)
168 traceback.print_exc()'''
170 class Engine(object):
172 Class used to communicate with the CuraEngine.
173 The CuraEngine is ran as a 2nd process and reports back information trough stderr.
174 GCode trough stdout and has a socket connection for polygon information and loading the 3D model into the engine.
176 GUI_CMD_REQUEST_MESH = 0x01
177 GUI_CMD_SEND_POLYGONS = 0x02
178 GUI_CMD_FINISH_OBJECT = 0x03
180 def __init__(self, progressCallback):
183 self._callback = progressCallback
184 self._progressSteps = ['inset', 'skin', 'export']
188 self._engine_executable = getEngineFilename()
189 self._serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
190 self._serverPortNr = 0xC20A
191 for potential_port in xrange(0xC20A, 0xFFFF):
192 self._serverPortNr = potential_port
194 self._serversocket.bind(('127.0.0.1', self._serverPortNr))
197 print("Failed to listen on port: %d" % (self._serverPortNr))
199 print("Failed to listen on any port, this is a fatal error")
201 thread = threading.Thread(target=self._socketListenThread)
205 def _socketListenThread(self):
206 self._serversocket.listen(1)
207 print 'Listening for engine communications on %d' % (self._serverPortNr)
210 sock, _ = self._serversocket.accept()
211 thread = threading.Thread(target=self._socketConnectionThread, args=(sock,))
214 except socket.error, e:
215 if e.errno != errno.EINTR:
218 def _socketConnectionThread(self, sock):
228 cmd = struct.unpack('@i', data)[0]
229 if cmd == self.GUI_CMD_REQUEST_MESH:
230 meshInfo = self._modelData[0]
231 self._modelData = self._modelData[1:]
232 sock.sendall(struct.pack('@i', meshInfo[0]))
233 sock.sendall(meshInfo[1].tostring())
234 elif cmd == self.GUI_CMD_SEND_POLYGONS:
235 cnt = struct.unpack('@i', sock.recv(4))[0]
236 layerNr = struct.unpack('@i', sock.recv(4))[0]
237 layerNr += layerNrOffset
238 z = struct.unpack('@i', sock.recv(4))[0]
239 z = float(z) / 1000.0
240 typeNameLen = struct.unpack('@i', sock.recv(4))[0]
241 typeName = sock.recv(typeNameLen)
242 while len(self._result._polygons) < layerNr + 1:
243 self._result._polygons.append({})
244 polygons = self._result._polygons[layerNr]
245 if typeName not in polygons:
246 polygons[typeName] = []
247 for n in xrange(0, cnt):
248 length = struct.unpack('@i', sock.recv(4))[0]
250 while len(data) < length * 8 * 2:
251 recvData = sock.recv(length * 8 * 2 - len(data))
252 if len(recvData) < 1:
255 polygon2d = numpy.array(numpy.fromstring(data, numpy.int64), numpy.float32) / 1000.0
256 polygon2d = polygon2d.reshape((len(polygon2d) / 2, 2))
257 polygon = numpy.empty((len(polygon2d), 3), numpy.float32)
258 polygon[:,:-1] = polygon2d
260 polygons[typeName].append(polygon)
261 elif cmd == self.GUI_CMD_FINISH_OBJECT:
262 layerNrOffset = len(self._result._polygons)
264 print "Unknown command on socket: %x" % (cmd)
269 self._serversocket.close()
271 def abortEngine(self):
272 if self._process is not None:
274 self._process.terminate()
279 if self._thread is not None:
285 def runEngine(self, scene):
286 if len(scene.objects()) < 1:
288 self._thread = threading.Thread(target=self._runEngine, args=(scene, self._thread, pluginInfo.getPostProcessPluginConfig()))
289 self._thread.daemon = True
292 def _runEngine(self, scene, old_thread, pluginConfig):
293 if old_thread is not None:
294 if self._process is not None:
295 self._process.terminate()
300 for obj in scene.objects():
301 if scene.checkPlatform(obj):
302 extruderCount = max(extruderCount, len(obj._meshList))
304 extruderCount = max(extruderCount, profile.minimalExtruderCount())
306 commandList = [self._engine_executable, '-v', '-p']
307 for k, v in self._engineSettings(extruderCount).iteritems():
308 commandList += ['-s', '%s=%s' % (k, str(v))]
309 commandList += ['-g', '%d' % (self._serverPortNr)]
312 hash = hashlib.sha512()
313 order = scene.printOrder()
315 pos = numpy.array(profile.getMachineCenterCoords()) * 1000
318 for obj in scene.objects():
319 if scene.checkPlatform(obj):
320 oMin = obj.getMinimum()[0:2] + obj.getPosition()
321 oMax = obj.getMaximum()[0:2] + obj.getPosition()
326 objMin[0] = min(oMin[0], objMin[0])
327 objMin[1] = min(oMin[1], objMin[1])
328 objMax[0] = max(oMax[0], objMax[0])
329 objMax[1] = max(oMax[1], objMax[1])
332 pos += (objMin + objMax) / 2.0 * 1000
333 commandList += ['-s', 'posx=%d' % int(pos[0]), '-s', 'posy=%d' % int(pos[1])]
335 vertexTotal = [0] * 4
337 for obj in scene.objects():
338 if scene.checkPlatform(obj):
339 meshMax = max(meshMax, len(obj._meshList))
340 for n in xrange(0, len(obj._meshList)):
341 vertexTotal[n] += obj._meshList[n].vertexCount
343 for n in xrange(0, meshMax):
344 verts = numpy.zeros((0, 3), numpy.float32)
345 for obj in scene.objects():
346 if scene.checkPlatform(obj):
347 if n < len(obj._meshList):
348 vertexes = (numpy.matrix(obj._meshList[n].vertexes, copy = False) * numpy.matrix(obj._matrix, numpy.float32)).getA()
349 vertexes -= obj._drawOffset
350 vertexes += numpy.array([obj.getPosition()[0], obj.getPosition()[1], 0.0])
351 verts = numpy.concatenate((verts, vertexes))
352 hash.update(obj._meshList[n].vertexes.tostring())
353 engineModelData.append((vertexTotal[n], verts))
355 commandList += ['$' * meshMax]
359 obj = scene.objects()[n]
360 for mesh in obj._meshList:
361 engineModelData.append((mesh.vertexCount, mesh.vertexes))
362 hash.update(mesh.vertexes.tostring())
363 pos = obj.getPosition() * 1000
364 pos += numpy.array(profile.getMachineCenterCoords()) * 1000
365 commandList += ['-m', ','.join(map(str, obj._matrix.getA().flatten()))]
366 commandList += ['-s', 'posx=%d' % int(pos[0]), '-s', 'posy=%d' % int(pos[1])]
367 commandList += ['$' * len(obj._meshList)]
369 modelHash = hash.hexdigest()
370 if self._objCount < 1:
372 if self._thread != threading.currentThread():
375 self._modelData = engineModelData
377 self._process = self._runEngineProcess(commandList)
379 traceback.print_exc()
382 self._result = EngineResult()
383 self._result.addLog('Running: %s' % (' '.join(commandList)))
384 self._result.setHash(modelHash)
387 logThread = threading.Thread(target=self._watchStderr, args=(self._process.stderr,))
388 logThread.daemon = True
392 data = self._process.stdout.read(4096)
394 if self._thread != threading.currentThread():
395 self._process.terminate()
396 self._result._gcodeData.write(data)
397 data = self._process.stdout.read(4096)
399 returnCode = self._process.wait()
401 self._result.addLog("Slicer process returned : %d" % returnCode)
403 plugin_error = pluginInfo.runPostProcessingPlugins(self._result, pluginConfig)
404 if plugin_error is not None:
405 self._result.addLog(plugin_error)
406 self._result.setFinished(True)
412 self._result.addLog("MemoryError")
416 with open(os.path.join(profile.getBasePath(), 'engine.log'), "w") as f:
417 for line in self._result.getLog():
422 def _watchStderr(self, stderr):
424 line = stderr.readline()
427 if line.startswith('Progress:'):
428 line = line.split(':')
429 if line[1] == 'process':
431 elif line[1] in self._progressSteps:
432 progressValue = float(line[2]) / float(line[3])
433 progressValue /= len(self._progressSteps)
434 progressValue += 1.0 / len(self._progressSteps) * self._progressSteps.index(line[1])
436 progressValue /= self._objCount
437 progressValue += 1.0 / self._objCount * objectNr
439 self._callback(progressValue)
442 elif line.startswith('Print time:'):
443 self._result._printTimeSeconds = int(line.split(':')[1].strip())
444 elif line.startswith('Filament:'):
445 self._result._filamentMM[0] = int(line.split(':')[1].strip())
446 if profile.getMachineSetting('gcode_flavor') == 'UltiGCode':
447 radius = profile.getProfileSettingFloat('filament_diameter') / 2.0
448 self._result._filamentMM[0] /= (math.pi * radius * radius)
449 elif line.startswith('Filament2:'):
450 self._result._filamentMM[1] = int(line.split(':')[1].strip())
451 if profile.getMachineSetting('gcode_flavor') == 'UltiGCode':
452 radius = profile.getProfileSettingFloat('filament_diameter') / 2.0
453 self._result._filamentMM[1] /= (math.pi * radius * radius)
454 elif line.startswith('Replace:'):
455 self._result._replaceInfo[line.split(':')[1].strip()] = line.split(':')[2].strip()
457 self._result.addLog(line)
458 line = stderr.readline()
460 def _engineSettings(self, extruderCount):
462 'layerThickness': int(profile.getProfileSettingFloat('layer_height') * 1000),
463 'initialLayerThickness': int(profile.getProfileSettingFloat('bottom_thickness') * 1000) if profile.getProfileSettingFloat('bottom_thickness') > 0.0 else int(profile.getProfileSettingFloat('layer_height') * 1000),
464 'filamentDiameter': int(profile.getProfileSettingFloat('filament_diameter') * 1000),
465 'filamentFlow': int(profile.getProfileSettingFloat('filament_flow')),
466 'extrusionWidth': int(profile.calculateEdgeWidth() * 1000),
467 'layer0extrusionWidth': int(profile.calculateEdgeWidth() * profile.getProfileSettingFloat('layer0_width_factor') / 100 * 1000),
468 'insetCount': int(profile.calculateLineCount()),
469 'downSkinCount': int(profile.calculateSolidLayerCount()) if profile.getProfileSetting('solid_bottom') == 'True' else 0,
470 'upSkinCount': int(profile.calculateSolidLayerCount()) if profile.getProfileSetting('solid_top') == 'True' else 0,
471 'infillOverlap': int(profile.getProfileSettingFloat('fill_overlap')),
472 'initialSpeedupLayers': int(4),
473 'initialLayerSpeed': int(profile.getProfileSettingFloat('bottom_layer_speed')),
474 'printSpeed': int(profile.getProfileSettingFloat('print_speed')),
475 'infillSpeed': int(profile.getProfileSettingFloat('infill_speed')) if int(profile.getProfileSettingFloat('infill_speed')) > 0 else int(profile.getProfileSettingFloat('print_speed')),
476 'inset0Speed': int(profile.getProfileSettingFloat('inset0_speed')) if int(profile.getProfileSettingFloat('inset0_speed')) > 0 else int(profile.getProfileSettingFloat('print_speed')),
477 'insetXSpeed': int(profile.getProfileSettingFloat('insetx_speed')) if int(profile.getProfileSettingFloat('insetx_speed')) > 0 else int(profile.getProfileSettingFloat('print_speed')),
478 'moveSpeed': int(profile.getProfileSettingFloat('travel_speed')),
479 'fanSpeedMin': int(profile.getProfileSettingFloat('fan_speed')) if profile.getProfileSetting('fan_enabled') == 'True' else 0,
480 'fanSpeedMax': int(profile.getProfileSettingFloat('fan_speed_max')) if profile.getProfileSetting('fan_enabled') == 'True' else 0,
481 'supportAngle': int(-1) if profile.getProfileSetting('support') == 'None' else int(profile.getProfileSettingFloat('support_angle')),
482 'supportEverywhere': int(1) if profile.getProfileSetting('support') == 'Everywhere' else int(0),
483 'supportLineDistance': int(100 * profile.calculateEdgeWidth() * 1000 / profile.getProfileSettingFloat('support_fill_rate')) if profile.getProfileSettingFloat('support_fill_rate') > 0 else -1,
484 'supportXYDistance': int(1000 * profile.getProfileSettingFloat('support_xy_distance')),
485 'supportZDistance': int(1000 * profile.getProfileSettingFloat('support_z_distance')),
486 '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),
487 'retractionAmount': int(profile.getProfileSettingFloat('retraction_amount') * 1000) if profile.getProfileSetting('retraction_enable') == 'True' else 0,
488 'retractionSpeed': int(profile.getProfileSettingFloat('retraction_speed')),
489 'retractionMinimalDistance': int(profile.getProfileSettingFloat('retraction_min_travel') * 1000),
490 'retractionAmountExtruderSwitch': int(profile.getProfileSettingFloat('retraction_dual_amount') * 1000),
491 'retractionZHop': int(profile.getProfileSettingFloat('retraction_hop') * 1000),
492 'minimalExtrusionBeforeRetraction': int(profile.getProfileSettingFloat('retraction_minimal_extrusion') * 1000),
493 'enableCombing': 1 if profile.getProfileSetting('retraction_combing') == 'True' else 0,
494 'multiVolumeOverlap': int(profile.getProfileSettingFloat('overlap_dual') * 1000),
495 'objectSink': max(0, int(profile.getProfileSettingFloat('object_sink') * 1000)),
496 'minimalLayerTime': int(profile.getProfileSettingFloat('cool_min_layer_time')),
497 'minimalFeedrate': int(profile.getProfileSettingFloat('cool_min_feedrate')),
498 'coolHeadLift': 1 if profile.getProfileSetting('cool_head_lift') == 'True' else 0,
499 'startCode': profile.getAlterationFileContents('start.gcode', extruderCount),
500 'endCode': profile.getAlterationFileContents('end.gcode', extruderCount),
501 'preSwitchExtruderCode': profile.getAlterationFileContents('preSwitchExtruder.gcode', extruderCount),
502 'postSwitchExtruderCode': profile.getAlterationFileContents('postSwitchExtruder.gcode', extruderCount),
504 'extruderOffset[1].X': int(profile.getMachineSettingFloat('extruder_offset_x1') * 1000),
505 'extruderOffset[1].Y': int(profile.getMachineSettingFloat('extruder_offset_y1') * 1000),
506 'extruderOffset[2].X': int(profile.getMachineSettingFloat('extruder_offset_x2') * 1000),
507 'extruderOffset[2].Y': int(profile.getMachineSettingFloat('extruder_offset_y2') * 1000),
508 'extruderOffset[3].X': int(profile.getMachineSettingFloat('extruder_offset_x3') * 1000),
509 'extruderOffset[3].Y': int(profile.getMachineSettingFloat('extruder_offset_y3') * 1000),
510 'zOffset': int(profile.getMachineSettingFloat('extruder_z_offset') * 1000),
513 fanFullHeight = int(profile.getProfileSettingFloat('fan_full_height') * 1000)
514 settings['fanFullOnLayerNr'] = (fanFullHeight - settings['initialLayerThickness'] - 1) / settings['layerThickness'] + 1
515 if settings['fanFullOnLayerNr'] < 0:
516 settings['fanFullOnLayerNr'] = 0
517 if profile.getProfileSetting('support_type') == 'Lines':
518 settings['supportType'] = 1
520 if profile.getProfileSettingFloat('fill_density') == 0:
521 settings['sparseInfillLineDistance'] = -1
522 elif profile.getProfileSettingFloat('fill_density') == 100:
523 settings['sparseInfillLineDistance'] = settings['extrusionWidth']
524 #Set the up/down skins height to 10000 if we want a 100% filled object.
525 # This gives better results then normal 100% infill as the sparse and up/down skin have some overlap.
526 settings['downSkinCount'] = 10000
527 settings['upSkinCount'] = 10000
529 settings['sparseInfillLineDistance'] = int(100 * profile.calculateEdgeWidth() * 1000 / profile.getProfileSettingFloat('fill_density'))
530 if profile.getProfileSetting('platform_adhesion') == 'Brim':
531 settings['skirtDistance'] = 0
532 settings['skirtLineCount'] = int(profile.getProfileSettingFloat('brim_line_count'))
533 elif profile.getProfileSetting('platform_adhesion') == 'Raft':
534 settings['skirtDistance'] = 0
535 settings['skirtLineCount'] = 0
536 settings['raftMargin'] = int(profile.getProfileSettingFloat('raft_margin') * 1000)
537 settings['raftLineSpacing'] = int(profile.getProfileSettingFloat('raft_line_spacing') * 1000)
538 settings['raftBaseThickness'] = int(profile.getProfileSettingFloat('raft_base_thickness') * 1000)
539 settings['raftBaseLinewidth'] = int(profile.getProfileSettingFloat('raft_base_linewidth') * 1000)
540 settings['raftInterfaceThickness'] = int(profile.getProfileSettingFloat('raft_interface_thickness') * 1000)
541 settings['raftInterfaceLinewidth'] = int(profile.getProfileSettingFloat('raft_interface_linewidth') * 1000)
542 settings['raftInterfaceLineSpacing'] = int(profile.getProfileSettingFloat('raft_interface_linewidth') * 1000 * 2.0)
543 settings['raftAirGapLayer0'] = int(profile.getProfileSettingFloat('raft_airgap') * 1000 + profile.getProfileSettingFloat('raft_airgap_all') * 1000)
544 settings['raftAirGap'] = int(profile.getProfileSettingFloat('raft_airgap_all') * 1000)
545 settings['raftBaseSpeed'] = int(profile.getProfileSettingFloat('bottom_layer_speed'))
546 settings['raftFanSpeed'] = 0
547 settings['raftSurfaceThickness'] = int(profile.getProfileSettingFloat('raft_surface_thickness') * 1000)
548 settings['raftSurfaceLinewidth'] = int(profile.getProfileSettingFloat('raft_surface_linewidth') * 1000)
549 settings['raftSurfaceLineSpacing'] = int(profile.getProfileSettingFloat('raft_surface_linewidth') * 1000)
550 settings['raftSurfaceLayers'] = int(profile.getProfileSettingFloat('raft_surface_layers'))
551 settings['raftSurfaceSpeed'] = int(profile.getProfileSettingFloat('bottom_layer_speed'))
553 settings['skirtDistance'] = int(profile.getProfileSettingFloat('skirt_gap') * 1000)
554 settings['skirtLineCount'] = int(profile.getProfileSettingFloat('skirt_line_count'))
555 settings['skirtMinLength'] = int(profile.getProfileSettingFloat('skirt_minimal_length') * 1000)
557 if profile.getProfileSetting('fix_horrible_union_all_type_a') == 'True':
558 settings['fixHorrible'] |= 0x01
559 if profile.getProfileSetting('fix_horrible_union_all_type_b') == 'True':
560 settings['fixHorrible'] |= 0x02
561 if profile.getProfileSetting('fix_horrible_use_open_bits') == 'True':
562 settings['fixHorrible'] |= 0x10
563 if profile.getProfileSetting('fix_horrible_extensive_stitching') == 'True':
564 settings['fixHorrible'] |= 0x04
566 if settings['layerThickness'] <= 0:
567 settings['layerThickness'] = 1000
568 if profile.getMachineSetting('gcode_flavor') == 'UltiGCode':
569 settings['gcodeFlavor'] = 1
570 elif profile.getMachineSetting('gcode_flavor') == 'MakerBot':
571 settings['gcodeFlavor'] = 2
572 elif profile.getMachineSetting('gcode_flavor') == 'BFB':
573 settings['gcodeFlavor'] = 3
574 elif profile.getMachineSetting('gcode_flavor') == 'Mach3':
575 settings['gcodeFlavor'] = 4
576 elif profile.getMachineSetting('gcode_flavor') == 'RepRap (Volumetric)':
577 settings['gcodeFlavor'] = 5
578 if profile.getProfileSetting('spiralize') == 'True':
579 settings['spiralizeMode'] = 1
580 if profile.getProfileSetting('simple_mode') == 'True':
581 settings['simpleMode'] = 1
582 if profile.getProfileSetting('wipe_tower') == 'True' and extruderCount > 1:
583 settings['wipeTowerSize'] = int(math.sqrt(profile.getProfileSettingFloat('wipe_tower_volume') * 1000 * 1000 * 1000 / settings['layerThickness']))
584 if profile.getProfileSetting('ooze_shield') == 'True':
585 settings['enableOozeShield'] = 1
588 def _runEngineProcess(self, cmdList):
590 if subprocess.mswindows:
591 su = subprocess.STARTUPINFO()
592 su.dwFlags |= subprocess.STARTF_USESHOWWINDOW
593 su.wShowWindow = subprocess.SW_HIDE
594 kwargs['startupinfo'] = su
595 kwargs['creationflags'] = 0x00004000 #BELOW_NORMAL_PRIORITY_CLASS
596 return subprocess.Popen(cmdList, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs)