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