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)
268 self._serversocket.close()
270 def abortEngine(self):
271 if self._process is not None:
273 self._process.terminate()
276 if self._thread is not None:
281 if self._thread is not None:
287 def runEngine(self, scene):
288 if len(scene.objects()) < 1:
291 for obj in scene.objects():
292 if scene.checkPlatform(obj):
293 extruderCount = max(extruderCount, len(obj._meshList))
295 extruderCount = max(extruderCount, profile.minimalExtruderCount())
297 commandList = [self._engine_executable, '-v', '-p']
298 for k, v in self._engineSettings(extruderCount).iteritems():
299 commandList += ['-s', '%s=%s' % (k, str(v))]
300 commandList += ['-g', '%d' % (self._serverPortNr)]
303 hash = hashlib.sha512()
304 order = scene.printOrder()
306 pos = numpy.array(profile.getMachineCenterCoords()) * 1000
309 for obj in scene.objects():
310 if scene.checkPlatform(obj):
311 oMin = obj.getMinimum()[0:2] + obj.getPosition()
312 oMax = obj.getMaximum()[0:2] + obj.getPosition()
317 objMin[0] = min(oMin[0], objMin[0])
318 objMin[1] = min(oMin[1], objMin[1])
319 objMax[0] = max(oMax[0], objMax[0])
320 objMax[1] = max(oMax[1], objMax[1])
323 pos += (objMin + objMax) / 2.0 * 1000
324 commandList += ['-s', 'posx=%d' % int(pos[0]), '-s', 'posy=%d' % int(pos[1])]
326 vertexTotal = [0] * 4
328 for obj in scene.objects():
329 if scene.checkPlatform(obj):
330 meshMax = max(meshMax, len(obj._meshList))
331 for n in xrange(0, len(obj._meshList)):
332 vertexTotal[n] += obj._meshList[n].vertexCount
334 for n in xrange(0, meshMax):
335 verts = numpy.zeros((0, 3), numpy.float32)
336 for obj in scene.objects():
337 if scene.checkPlatform(obj):
338 if n < len(obj._meshList):
339 vertexes = (numpy.matrix(obj._meshList[n].vertexes, copy = False) * numpy.matrix(obj._matrix, numpy.float32)).getA()
340 vertexes -= obj._drawOffset
341 vertexes += numpy.array([obj.getPosition()[0], obj.getPosition()[1], 0.0])
342 verts = numpy.concatenate((verts, vertexes))
343 hash.update(obj._meshList[n].vertexes.tostring())
344 engineModelData.append((vertexTotal[n], verts))
346 commandList += ['$' * meshMax]
350 obj = scene.objects()[n]
351 for mesh in obj._meshList:
352 engineModelData.append((mesh.vertexCount, mesh.vertexes))
353 hash.update(mesh.vertexes.tostring())
354 pos = obj.getPosition() * 1000
355 pos += numpy.array(profile.getMachineCenterCoords()) * 1000
356 commandList += ['-m', ','.join(map(str, obj._matrix.getA().flatten()))]
357 commandList += ['-s', 'posx=%d' % int(pos[0]), '-s', 'posy=%d' % int(pos[1])]
358 commandList += ['$' * len(obj._meshList)]
360 modelHash = hash.hexdigest()
361 if self._objCount > 0:
362 self._thread = threading.Thread(target=self._watchProcess, args=(commandList, self._thread, engineModelData, modelHash, pluginInfo.getPostProcessPluginConfig()))
363 self._thread.daemon = True
366 def _watchProcess(self, commandList, oldThread, engineModelData, modelHash, pluginConfig):
367 if oldThread is not None:
368 if self._process is not None:
369 self._process.terminate()
372 self._modelData = engineModelData
374 self._process = self._runEngineProcess(commandList)
376 traceback.print_exc()
378 if self._thread != threading.currentThread():
379 self._process.terminate()
381 self._result = EngineResult()
382 self._result.addLog('Running: %s' % (' '.join(commandList)))
383 self._result.setHash(modelHash)
386 logThread = threading.Thread(target=self._watchStderr, args=(self._process.stderr,))
387 logThread.daemon = True
391 data = self._process.stdout.read(4096)
393 self._result._gcodeData.write(data)
394 data = self._process.stdout.read(4096)
396 returnCode = self._process.wait()
398 self._result.addLog("Slicer process returned : %d" % returnCode)
400 plugin_error = pluginInfo.runPostProcessingPlugins(self._result, pluginConfig)
401 if plugin_error is not None:
402 self._result.addLog(plugin_error)
403 self._result.setFinished(True)
409 self._result.addLog("MemoryError")
413 with open(os.path.join(profile.getBasePath(), 'engine.log'), "w") as f:
414 for line in self._result.getLog():
419 def _watchStderr(self, stderr):
421 line = stderr.readline()
424 if line.startswith('Progress:'):
425 line = line.split(':')
426 if line[1] == 'process':
428 elif line[1] in self._progressSteps:
429 progressValue = float(line[2]) / float(line[3])
430 progressValue /= len(self._progressSteps)
431 progressValue += 1.0 / len(self._progressSteps) * self._progressSteps.index(line[1])
433 progressValue /= self._objCount
434 progressValue += 1.0 / self._objCount * objectNr
436 self._callback(progressValue)
439 elif line.startswith('Print time:'):
440 self._result._printTimeSeconds = int(line.split(':')[1].strip())
441 elif line.startswith('Filament:'):
442 self._result._filamentMM[0] = int(line.split(':')[1].strip())
443 if profile.getMachineSetting('gcode_flavor') == 'UltiGCode':
444 radius = profile.getProfileSettingFloat('filament_diameter') / 2.0
445 self._result._filamentMM[0] /= (math.pi * radius * radius)
446 elif line.startswith('Filament2:'):
447 self._result._filamentMM[1] = int(line.split(':')[1].strip())
448 if profile.getMachineSetting('gcode_flavor') == 'UltiGCode':
449 radius = profile.getProfileSettingFloat('filament_diameter') / 2.0
450 self._result._filamentMM[1] /= (math.pi * radius * radius)
451 elif line.startswith('Replace:'):
452 self._result._replaceInfo[line.split(':')[1].strip()] = line.split(':')[2].strip()
454 self._result.addLog(line)
455 line = stderr.readline()
457 def _engineSettings(self, extruderCount):
459 'layerThickness': int(profile.getProfileSettingFloat('layer_height') * 1000),
460 'initialLayerThickness': int(profile.getProfileSettingFloat('bottom_thickness') * 1000) if profile.getProfileSettingFloat('bottom_thickness') > 0.0 else int(profile.getProfileSettingFloat('layer_height') * 1000),
461 'filamentDiameter': int(profile.getProfileSettingFloat('filament_diameter') * 1000),
462 'filamentFlow': int(profile.getProfileSettingFloat('filament_flow')),
463 'extrusionWidth': int(profile.calculateEdgeWidth() * 1000),
464 'layer0extrusionWidth': int(profile.calculateEdgeWidth() * profile.getProfileSettingFloat('layer0_width_factor') / 100 * 1000),
465 'insetCount': int(profile.calculateLineCount()),
466 'downSkinCount': int(profile.calculateSolidLayerCount()) if profile.getProfileSetting('solid_bottom') == 'True' else 0,
467 'upSkinCount': int(profile.calculateSolidLayerCount()) if profile.getProfileSetting('solid_top') == 'True' else 0,
468 'infillOverlap': int(profile.getProfileSettingFloat('fill_overlap')),
469 'initialSpeedupLayers': int(4),
470 'initialLayerSpeed': int(profile.getProfileSettingFloat('bottom_layer_speed')),
471 'printSpeed': int(profile.getProfileSettingFloat('print_speed')),
472 'infillSpeed': int(profile.getProfileSettingFloat('infill_speed')) if int(profile.getProfileSettingFloat('infill_speed')) > 0 else int(profile.getProfileSettingFloat('print_speed')),
473 'inset0Speed': int(profile.getProfileSettingFloat('inset0_speed')) if int(profile.getProfileSettingFloat('inset0_speed')) > 0 else int(profile.getProfileSettingFloat('print_speed')),
474 'insetXSpeed': int(profile.getProfileSettingFloat('insetx_speed')) if int(profile.getProfileSettingFloat('insetx_speed')) > 0 else int(profile.getProfileSettingFloat('print_speed')),
475 'moveSpeed': int(profile.getProfileSettingFloat('travel_speed')),
476 'fanSpeedMin': int(profile.getProfileSettingFloat('fan_speed')) if profile.getProfileSetting('fan_enabled') == 'True' else 0,
477 'fanSpeedMax': int(profile.getProfileSettingFloat('fan_speed_max')) if profile.getProfileSetting('fan_enabled') == 'True' else 0,
478 'supportAngle': int(-1) if profile.getProfileSetting('support') == 'None' else int(profile.getProfileSettingFloat('support_angle')),
479 'supportEverywhere': int(1) if profile.getProfileSetting('support') == 'Everywhere' else int(0),
480 'supportLineDistance': int(100 * profile.calculateEdgeWidth() * 1000 / profile.getProfileSettingFloat('support_fill_rate')) if profile.getProfileSettingFloat('support_fill_rate') > 0 else -1,
481 'supportXYDistance': int(1000 * profile.getProfileSettingFloat('support_xy_distance')),
482 'supportZDistance': int(1000 * profile.getProfileSettingFloat('support_z_distance')),
483 '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),
484 'retractionAmount': int(profile.getProfileSettingFloat('retraction_amount') * 1000) if profile.getProfileSetting('retraction_enable') == 'True' else 0,
485 'retractionSpeed': int(profile.getProfileSettingFloat('retraction_speed')),
486 'retractionMinimalDistance': int(profile.getProfileSettingFloat('retraction_min_travel') * 1000),
487 'retractionAmountExtruderSwitch': int(profile.getProfileSettingFloat('retraction_dual_amount') * 1000),
488 'retractionZHop': int(profile.getProfileSettingFloat('retraction_hop') * 1000),
489 'minimalExtrusionBeforeRetraction': int(profile.getProfileSettingFloat('retraction_minimal_extrusion') * 1000),
490 'enableCombing': 1 if profile.getProfileSetting('retraction_combing') == 'True' else 0,
491 'multiVolumeOverlap': int(profile.getProfileSettingFloat('overlap_dual') * 1000),
492 'objectSink': max(0, int(profile.getProfileSettingFloat('object_sink') * 1000)),
493 'minimalLayerTime': int(profile.getProfileSettingFloat('cool_min_layer_time')),
494 'minimalFeedrate': int(profile.getProfileSettingFloat('cool_min_feedrate')),
495 'coolHeadLift': 1 if profile.getProfileSetting('cool_head_lift') == 'True' else 0,
496 'startCode': profile.getAlterationFileContents('start.gcode', extruderCount),
497 'endCode': profile.getAlterationFileContents('end.gcode', extruderCount),
498 'preSwitchExtruderCode': profile.getAlterationFileContents('preSwitchExtruder.gcode', extruderCount),
499 'postSwitchExtruderCode': profile.getAlterationFileContents('postSwitchExtruder.gcode', extruderCount),
501 'extruderOffset[1].X': int(profile.getMachineSettingFloat('extruder_offset_x1') * 1000),
502 'extruderOffset[1].Y': int(profile.getMachineSettingFloat('extruder_offset_y1') * 1000),
503 'extruderOffset[2].X': int(profile.getMachineSettingFloat('extruder_offset_x2') * 1000),
504 'extruderOffset[2].Y': int(profile.getMachineSettingFloat('extruder_offset_y2') * 1000),
505 'extruderOffset[3].X': int(profile.getMachineSettingFloat('extruder_offset_x3') * 1000),
506 'extruderOffset[3].Y': int(profile.getMachineSettingFloat('extruder_offset_y3') * 1000),
507 'zOffset': int(profile.getMachineSettingFloat('extruder_z_offset') * 1000),
510 fanFullHeight = int(profile.getProfileSettingFloat('fan_full_height') * 1000)
511 settings['fanFullOnLayerNr'] = (fanFullHeight - settings['initialLayerThickness'] - 1) / settings['layerThickness'] + 1
512 if settings['fanFullOnLayerNr'] < 0:
513 settings['fanFullOnLayerNr'] = 0
514 if profile.getProfileSetting('support_type') == 'Lines':
515 settings['supportType'] = 1
517 if profile.getProfileSettingFloat('fill_density') == 0:
518 settings['sparseInfillLineDistance'] = -1
519 elif profile.getProfileSettingFloat('fill_density') == 100:
520 settings['sparseInfillLineDistance'] = settings['extrusionWidth']
521 #Set the up/down skins height to 10000 if we want a 100% filled object.
522 # This gives better results then normal 100% infill as the sparse and up/down skin have some overlap.
523 settings['downSkinCount'] = 10000
524 settings['upSkinCount'] = 10000
526 settings['sparseInfillLineDistance'] = int(100 * profile.calculateEdgeWidth() * 1000 / profile.getProfileSettingFloat('fill_density'))
527 if profile.getProfileSetting('platform_adhesion') == 'Brim':
528 settings['skirtDistance'] = 0
529 settings['skirtLineCount'] = int(profile.getProfileSettingFloat('brim_line_count'))
530 elif profile.getProfileSetting('platform_adhesion') == 'Raft':
531 settings['skirtDistance'] = 0
532 settings['skirtLineCount'] = 0
533 settings['raftMargin'] = int(profile.getProfileSettingFloat('raft_margin') * 1000)
534 settings['raftLineSpacing'] = int(profile.getProfileSettingFloat('raft_line_spacing') * 1000)
535 settings['raftBaseThickness'] = int(profile.getProfileSettingFloat('raft_base_thickness') * 1000)
536 settings['raftBaseLinewidth'] = int(profile.getProfileSettingFloat('raft_base_linewidth') * 1000)
537 settings['raftInterfaceThickness'] = int(profile.getProfileSettingFloat('raft_interface_thickness') * 1000)
538 settings['raftInterfaceLinewidth'] = int(profile.getProfileSettingFloat('raft_interface_linewidth') * 1000)
539 settings['raftInterfaceLineSpacing'] = int(profile.getProfileSettingFloat('raft_interface_linewidth') * 1000 * 2.0)
540 settings['raftAirGapLayer0'] = int(profile.getProfileSettingFloat('raft_airgap') * 1000 + profile.getProfileSettingFloat('raft_airgap_all') * 1000)
541 settings['raftAirGap'] = int(profile.getProfileSettingFloat('raft_airgap_all') * 1000)
542 settings['raftBaseSpeed'] = int(profile.getProfileSettingFloat('bottom_layer_speed'))
543 settings['raftFanSpeed'] = 0
544 settings['raftSurfaceThickness'] = int(profile.getProfileSettingFloat('raft_surface_thickness') * 1000)
545 settings['raftSurfaceLinewidth'] = int(profile.getProfileSettingFloat('raft_surface_linewidth') * 1000)
546 settings['raftSurfaceLineSpacing'] = int(profile.getProfileSettingFloat('raft_surface_linewidth') * 1000)
547 settings['raftSurfaceLayers'] = int(profile.getProfileSettingFloat('raft_surface_layers'))
548 settings['raftSurfaceSpeed'] = int(profile.getProfileSettingFloat('bottom_layer_speed'))
550 settings['skirtDistance'] = int(profile.getProfileSettingFloat('skirt_gap') * 1000)
551 settings['skirtLineCount'] = int(profile.getProfileSettingFloat('skirt_line_count'))
552 settings['skirtMinLength'] = int(profile.getProfileSettingFloat('skirt_minimal_length') * 1000)
554 if profile.getProfileSetting('fix_horrible_union_all_type_a') == 'True':
555 settings['fixHorrible'] |= 0x01
556 if profile.getProfileSetting('fix_horrible_union_all_type_b') == 'True':
557 settings['fixHorrible'] |= 0x02
558 if profile.getProfileSetting('fix_horrible_use_open_bits') == 'True':
559 settings['fixHorrible'] |= 0x10
560 if profile.getProfileSetting('fix_horrible_extensive_stitching') == 'True':
561 settings['fixHorrible'] |= 0x04
563 if settings['layerThickness'] <= 0:
564 settings['layerThickness'] = 1000
565 if profile.getMachineSetting('gcode_flavor') == 'UltiGCode':
566 settings['gcodeFlavor'] = 1
567 elif profile.getMachineSetting('gcode_flavor') == 'MakerBot':
568 settings['gcodeFlavor'] = 2
569 elif profile.getMachineSetting('gcode_flavor') == 'BFB':
570 settings['gcodeFlavor'] = 3
571 elif profile.getMachineSetting('gcode_flavor') == 'Mach3':
572 settings['gcodeFlavor'] = 4
573 elif profile.getMachineSetting('gcode_flavor') == 'RepRap (Volumetric)':
574 settings['gcodeFlavor'] = 5
575 if profile.getProfileSetting('spiralize') == 'True':
576 settings['spiralizeMode'] = 1
577 if profile.getProfileSetting('simple_mode') == 'True':
578 settings['simpleMode'] = 1
579 if profile.getProfileSetting('wipe_tower') == 'True' and extruderCount > 1:
580 settings['wipeTowerSize'] = int(math.sqrt(profile.getProfileSettingFloat('wipe_tower_volume') * 1000 * 1000 * 1000 / settings['layerThickness']))
581 if profile.getProfileSetting('ooze_shield') == 'True':
582 settings['enableOozeShield'] = 1
585 def _runEngineProcess(self, cmdList):
587 if subprocess.mswindows:
588 su = subprocess.STARTUPINFO()
589 su.dwFlags |= subprocess.STARTF_USESHOWWINDOW
590 su.wShowWindow = subprocess.SW_HIDE
591 kwargs['startupinfo'] = su
592 kwargs['creationflags'] = 0x00004000 #BELOW_NORMAL_PRIORITY_CLASS
593 return subprocess.Popen(cmdList, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs)