+__copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
import subprocess
import time
import math
import traceback
import platform
import sys
+import urllib
+import urllib2
+import hashlib
+import cStringIO as StringIO
from Cura.util import profile
+from Cura.util import version
+from Cura.util import gcodeInterpreter
def getEngineFilename():
if platform.system() == 'Windows':
- if os.path.exists('C:/Software/Cura_SteamEngine/_bin/Release/Cura_SteamEngine.exe'):
+ if version.isDevVersion() and os.path.exists('C:/Software/Cura_SteamEngine/_bin/Release/Cura_SteamEngine.exe'):
return 'C:/Software/Cura_SteamEngine/_bin/Release/Cura_SteamEngine.exe'
- return os.path.abspath(os.path.join(os.path.dirname(__file__), '../..', 'SteamEngine.exe'))
+ return os.path.abspath(os.path.join(os.path.dirname(__file__), '../..', 'CuraEngine.exe'))
if hasattr(sys, 'frozen'):
- return os.path.abspath(os.path.join(os.path.dirname(__file__), '../../../../..', 'SteamEngine'))
- return os.path.abspath(os.path.join(os.path.dirname(__file__), '../..', 'SteamEngine'))
+ return os.path.abspath(os.path.join(os.path.dirname(__file__), '../../../../..', 'CuraEngine'))
+ if os.path.isfile('/usr/bin/CuraEngine'):
+ return '/usr/bin/CuraEngine'
+ if os.path.isfile('/usr/local/bin/CuraEngine'):
+ return '/usr/local/bin/CuraEngine'
+ return os.path.abspath(os.path.join(os.path.dirname(__file__), '../..', 'CuraEngine'))
def getTempFilename():
warnings.simplefilter('ignore')
warnings.simplefilter('default')
return ret
-class Slicer(object):
+class EngineResult(object):
+ def __init__(self):
+ self._engineLog = []
+ self._gcodeData = StringIO.StringIO()
+ self._polygons = []
+ self._success = False
+ self._printTimeSeconds = None
+ self._filamentMM = [0.0] * 4
+ self._modelHash = None
+ self._profileString = profile.getProfileString()
+ self._preferencesString = profile.getPreferencesString()
+ self._gcodeInterpreter = gcodeInterpreter.gcode()
+ self._gcodeLoadThread = None
+ self._finished = False
+
+ def getFilamentWeight(self, e=0):
+ #Calculates the weight of the filament in kg
+ radius = float(profile.getProfileSetting('filament_diameter')) / 2
+ volumeM3 = (self._filamentMM[e] * (math.pi * radius * radius)) / (1000*1000*1000)
+ return volumeM3 * profile.getPreferenceFloat('filament_physical_density')
+
+ def getFilamentCost(self, e=0):
+ cost_kg = profile.getPreferenceFloat('filament_cost_kg')
+ cost_meter = profile.getPreferenceFloat('filament_cost_meter')
+ if cost_kg > 0.0 and cost_meter > 0.0:
+ return "%.2f / %.2f" % (self.getFilamentWeight(e) * cost_kg, self._filamentMM[e] / 1000.0 * cost_meter)
+ elif cost_kg > 0.0:
+ return "%.2f" % (self.getFilamentWeight(e) * cost_kg)
+ elif cost_meter > 0.0:
+ return "%.2f" % (self._filamentMM[e] / 1000.0 * cost_meter)
+ return None
+
+ def getPrintTime(self):
+ if int(self._printTimeSeconds / 60 / 60) < 1:
+ return '%d minutes' % (int(self._printTimeSeconds / 60) % 60)
+ if int(self._printTimeSeconds / 60 / 60) == 1:
+ return '%d hour %d minutes' % (int(self._printTimeSeconds / 60 / 60), int(self._printTimeSeconds / 60) % 60)
+ return '%d hours %d minutes' % (int(self._printTimeSeconds / 60 / 60), int(self._printTimeSeconds / 60) % 60)
+
+ def getFilamentAmount(self, e=0):
+ if self._filamentMM[e] == 0.0:
+ return None
+ return '%0.2f meter %0.0f gram' % (float(self._filamentMM[e]) / 1000.0, self.getFilamentWeight(e) * 1000.0)
+
+ def getLog(self):
+ return self._engineLog
+
+ def getGCode(self):
+ return self._gcodeData.getvalue()
+
+ def addLog(self, line):
+ self._engineLog.append(line)
+
+ def setHash(self, hash):
+ self._modelHash = hash
+
+ def setFinished(self, result):
+ self._finished = result
+
+ def isFinished(self):
+ return self._finished
+
+ def getGCodeLayers(self):
+ if not self._finished:
+ return None
+ if self._gcodeInterpreter.layerList is None and self._gcodeLoadThread is None:
+ self._gcodeInterpreter.progressCallback = self._gcodeInterpreterCallback
+ self._gcodeLoadThread = threading.Thread(target=lambda : self._gcodeInterpreter.load(self._gcodeData))
+ self._gcodeLoadThread.daemon = True
+ self._gcodeLoadThread.start()
+ return self._gcodeInterpreter.layerList
+
+ def _gcodeInterpreterCallback(self, progress):
+ if len(self._gcodeInterpreter.layerList) % 15 == 0:
+ time.sleep(0.1)
+ return False
+
+ def submitInfoOnline(self):
+ if profile.getPreference('submit_slice_information') != 'True':
+ return
+ if version.isDevVersion():
+ return
+ data = {
+ 'processor': platform.processor(),
+ 'machine': platform.machine(),
+ 'platform': platform.platform(),
+ 'profile': self._profileString,
+ 'preferences': self._preferencesString,
+ 'modelhash': self._modelHash,
+ 'version': version.getVersion(),
+ }
+ try:
+ f = urllib2.urlopen("http://www.youmagine.com/curastats/", data = urllib.urlencode(data), timeout = 1)
+ f.read()
+ f.close()
+ except:
+ pass
+
+class Engine(object):
def __init__(self, progressCallback):
self._process = None
self._thread = None
self._callback = progressCallback
self._binaryStorageFilename = getTempFilename()
- self._exportFilename = getTempFilename()
self._progressSteps = ['inset', 'skin', 'export']
self._objCount = 0
- self._sliceLog = []
- self._printTimeSeconds = None
- self._filamentMM = None
+ self._result = None
def cleanup(self):
- self.abortSlicer()
+ self.abortEngine()
try:
os.remove(self._binaryStorageFilename)
except:
pass
- try:
- os.remove(self._exportFilename)
- except:
- pass
- def abortSlicer(self):
+ def abortEngine(self):
if self._process is not None:
try:
self._process.terminate()
except:
pass
+ if self._thread is not None:
self._thread.join()
+ self._thread = None
- def getGCodeFilename(self):
- return self._exportFilename
-
- def getSliceLog(self):
- return self._sliceLog
-
- def getFilamentWeight(self):
- #Calculates the weight of the filament in kg
- radius = float(profile.getProfileSetting('filament_diameter')) / 2
- volumeM3 = (self._filamentMM * (math.pi * radius * radius)) / (1000*1000*1000)
- return volumeM3 * profile.getPreferenceFloat('filament_physical_density')
-
- def getFilamentCost(self):
- cost_kg = profile.getPreferenceFloat('filament_cost_kg')
- cost_meter = profile.getPreferenceFloat('filament_cost_meter')
- if cost_kg > 0.0 and cost_meter > 0.0:
- return "%.2f / %.2f" % (self.getFilamentWeight() * cost_kg, self._filamentMM / 1000.0 * cost_meter)
- elif cost_kg > 0.0:
- return "%.2f" % (self.getFilamentWeight() * cost_kg)
- elif cost_meter > 0.0:
- return "%.2f" % (self._filamentMM / 1000.0 * cost_meter)
- return None
+ def wait(self):
+ if self._thread is not None:
+ self._thread.join()
- def getPrintTime(self):
- return '%02d:%02d' % (int(self._printTimeSeconds / 60 / 60), int(self._printTimeSeconds / 60) % 60)
+ def getResult(self):
+ return self._result
- def getFilamentAmount(self):
- return '%0.2fm %0.0fgram' % (float(self._filamentMM) / 1000.0, self.getFilamentWeight() * 1000.0)
+ def runEngine(self, scene):
+ if len(scene.objects()) < 1:
+ return
+ extruderCount = 1
+ for obj in scene.objects():
+ if scene.checkPlatform(obj):
+ extruderCount = max(extruderCount, len(obj._meshList))
- def runSlicer(self, scene):
- self.abortSlicer()
- self._callback(-1.0, False)
+ extruderCount = max(extruderCount, profile.minimalExtruderCount())
- commandList = [getEngineFilename(), '-vv']
- for k, v in self._engineSettings().iteritems():
+ commandList = [getEngineFilename(), '-vvv']
+ for k, v in self._engineSettings(extruderCount).iteritems():
commandList += ['-s', '%s=%s' % (k, str(v))]
- commandList += ['-o', self._exportFilename]
commandList += ['-b', self._binaryStorageFilename]
self._objCount = 0
with open(self._binaryStorageFilename, "wb") as f:
+ hash = hashlib.sha512()
order = scene.printOrder()
if order is None:
- pos = numpy.array([profile.getPreferenceFloat('machine_width') * 1000 / 2, profile.getPreferenceFloat('machine_depth') * 1000 / 2])
- commandList += ['-s', 'posx=%d' % int(pos[0]), '-s', 'posy=%d' % int(pos[1])]
-
- vertexTotal = 0
+ pos = numpy.array(profile.getMachineCenterCoords()) * 1000
+ objMin = None
+ objMax = None
for obj in scene.objects():
if scene.checkPlatform(obj):
- for mesh in obj._meshList:
- vertexTotal += mesh.vertexCount
+ oMin = obj.getMinimum()[0:2] + obj.getPosition()
+ oMax = obj.getMaximum()[0:2] + obj.getPosition()
+ if objMin is None:
+ objMin = oMin
+ objMax = oMax
+ else:
+ objMin[0] = min(oMin[0], objMin[0])
+ objMin[1] = min(oMin[1], objMin[1])
+ objMax[0] = max(oMax[0], objMax[0])
+ objMax[1] = max(oMax[1], objMax[1])
+ if objMin is None:
+ return
+ pos += (objMin + objMax) / 2.0 * 1000
+ commandList += ['-s', 'posx=%d' % int(pos[0]), '-s', 'posy=%d' % int(pos[1])]
- f.write(numpy.array([vertexTotal], numpy.int32).tostring())
+ vertexTotal = [0] * 4
+ meshMax = 1
for obj in scene.objects():
if scene.checkPlatform(obj):
- for mesh in obj._meshList:
- vertexes = (numpy.matrix(mesh.vertexes, copy = False) * numpy.matrix(obj._matrix, numpy.float32)).getA()
- vertexes -= obj._drawOffset
- vertexes += numpy.array([obj.getPosition()[0], obj.getPosition()[1], 0.0])
- f.write(vertexes.tostring())
+ meshMax = max(meshMax, len(obj._meshList))
+ for n in xrange(0, len(obj._meshList)):
+ vertexTotal[n] += obj._meshList[n].vertexCount
- commandList += ['#']
+ for n in xrange(0, meshMax):
+ f.write(numpy.array([vertexTotal[n]], numpy.int32).tostring())
+ for obj in scene.objects():
+ if scene.checkPlatform(obj):
+ if n < len(obj._meshList):
+ vertexes = (numpy.matrix(obj._meshList[n].vertexes, copy = False) * numpy.matrix(obj._matrix, numpy.float32)).getA()
+ vertexes -= obj._drawOffset
+ vertexes += numpy.array([obj.getPosition()[0], obj.getPosition()[1], 0.0])
+ f.write(vertexes.tostring())
+ hash.update(obj._meshList[n].vertexes.tostring())
+
+ commandList += ['#' * meshMax]
self._objCount = 1
else:
for n in order:
obj = scene.objects()[n]
for mesh in obj._meshList:
f.write(numpy.array([mesh.vertexCount], numpy.int32).tostring())
- f.write(mesh.vertexes.tostring())
+ s = mesh.vertexes.tostring()
+ f.write(s)
+ hash.update(s)
pos = obj.getPosition() * 1000
- pos += numpy.array([profile.getPreferenceFloat('machine_width') * 1000 / 2, profile.getPreferenceFloat('machine_depth') * 1000 / 2])
+ pos += numpy.array(profile.getMachineCenterCoords()) * 1000
commandList += ['-m', ','.join(map(str, obj._matrix.getA().flatten()))]
commandList += ['-s', 'posx=%d' % int(pos[0]), '-s', 'posy=%d' % int(pos[1])]
commandList += ['#' * len(obj._meshList)]
self._objCount += 1
+ modelHash = hash.hexdigest()
if self._objCount > 0:
- try:
- self._process = self._runSliceProcess(commandList)
- self._thread = threading.Thread(target=self._watchProcess)
- self._thread.daemon = True
- self._thread.start()
- except OSError:
- traceback.print_exc()
-
- def _watchProcess(self):
- self._callback(0.0, False)
- self._sliceLog = []
- self._printTimeSeconds = None
- self._filamentMM = None
+ self._thread = threading.Thread(target=self._watchProcess, args=(commandList, self._thread, modelHash))
+ self._thread.daemon = True
+ self._thread.start()
+
+ def _watchProcess(self, commandList, oldThread, modelHash):
+ if oldThread is not None:
+ if self._process is not None:
+ self._process.terminate()
+ oldThread.join()
+ self._callback(-1.0)
+ try:
+ self._process = self._runEngineProcess(commandList)
+ except OSError:
+ traceback.print_exc()
+ return
+ if self._thread != threading.currentThread():
+ self._process.terminate()
- line = self._process.stdout.readline()
+ self._result = EngineResult()
+ self._result.setHash(modelHash)
+ self._callback(0.0)
+
+ logThread = threading.Thread(target=self._watchStderr, args=(self._process.stderr,))
+ logThread.daemon = True
+ logThread.start()
+
+ data = self._process.stdout.read(4096)
+ while len(data) > 0:
+ self._result._gcodeData.write(data)
+ data = self._process.stdout.read(4096)
+
+ returnCode = self._process.wait()
+ logThread.join()
+ if returnCode == 0:
+ pluginError = None #profile.runPostProcessingPlugins(self._exportFilename)
+ if pluginError is not None:
+ print pluginError
+ self._result.addLog(pluginError)
+ self._result.setFinished(True)
+ self._callback(1.0)
+ else:
+ for line in self._result.getLog():
+ print line
+ self._callback(-1.0)
+ self._process = None
+
+ def _watchStderr(self, stderr):
objectNr = 0
- while len(line):
+
+ # data = stderr.read(4096)
+ # tmp = StringIO.StringIO()
+ # while len(data):
+ # tmp.write(data)
+ # data = stderr.read(4096)
+ # stderr = StringIO.StringIO(tmp.getvalue())
+
+ line = stderr.readline()
+ while len(line) > 0:
line = line.strip()
if line.startswith('Progress:'):
line = line.split(':')
progressValue /= self._objCount
progressValue += 1.0 / self._objCount * objectNr
try:
- self._callback(progressValue, False)
+ self._callback(progressValue)
except:
pass
+ elif line.startswith('Polygons:'):
+ line = line.split(':')
+ typeName = line[1]
+ layerNr = int(line[2])
+ size = int(line[3])
+ z = float(line[4])
+ while len(self._result._polygons) < layerNr + 1:
+ self._result._polygons.append({})
+ polygons = self._result._polygons[layerNr]
+ for n in xrange(0, size):
+ polygon = stderr.readline().strip()
+ if not polygon:
+ continue
+ polygon2d = numpy.fromstring(polygon, dtype=numpy.float32, sep=' ')
+ polygon2d = polygon2d.reshape((len(polygon2d) / 2, 2))
+ polygon = numpy.empty((len(polygon2d), 3), numpy.float32)
+ polygon[:,:-1] = polygon2d
+ polygon[:,2] = z
+ if typeName not in polygons:
+ polygons[typeName] = []
+ polygons[typeName].append(polygon)
elif line.startswith('Print time:'):
- self._printTimeSeconds = int(line.split(':')[1].strip())
+ self._result._printTimeSeconds = int(line.split(':')[1].strip())
elif line.startswith('Filament:'):
- self._filamentMM = int(line.split(':')[1].strip())
+ self._result._filamentMM[0] = int(line.split(':')[1].strip())
+ if profile.getMachineSetting('gcode_flavor') == 'UltiGCode':
+ radius = profile.getProfileSettingFloat('filament_diameter') / 2.0
+ self._result._filamentMM[0] /= (math.pi * radius * radius)
+ elif line.startswith('Filament2:'):
+ self._result._filamentMM[1] = int(line.split(':')[1].strip())
+ if profile.getMachineSetting('gcode_flavor') == 'UltiGCode':
+ radius = profile.getProfileSettingFloat('filament_diameter') / 2.0
+ self._result._filamentMM[1] /= (math.pi * radius * radius)
else:
- self._sliceLog.append(line.strip())
- line = self._process.stdout.readline()
- for line in self._process.stderr:
- self._sliceLog.append(line.strip())
- returnCode = self._process.wait()
- try:
- if returnCode == 0:
- self._callback(1.0, True)
- else:
- self._callback(-1.0, False)
- except:
- pass
- self._process = None
+ self._result.addLog(line)
+ line = stderr.readline()
- def _engineSettings(self):
- return {
+ def _engineSettings(self, extruderCount):
+ settings = {
'layerThickness': int(profile.getProfileSettingFloat('layer_height') * 1000),
- 'initialLayerThickness': int(profile.getProfileSettingFloat('bottom_thickness') * 1000),
+ 'initialLayerThickness': int(profile.getProfileSettingFloat('bottom_thickness') * 1000) if profile.getProfileSettingFloat('bottom_thickness') > 0.0 else int(profile.getProfileSettingFloat('layer_height') * 1000),
'filamentDiameter': int(profile.getProfileSettingFloat('filament_diameter') * 1000),
+ 'filamentFlow': int(profile.getProfileSettingFloat('filament_flow')),
'extrusionWidth': int(profile.calculateEdgeWidth() * 1000),
'insetCount': int(profile.calculateLineCount()),
'downSkinCount': int(profile.calculateSolidLayerCount()) if profile.getProfileSetting('solid_bottom') == 'True' else 0,
'upSkinCount': int(profile.calculateSolidLayerCount()) if profile.getProfileSetting('solid_top') == 'True' else 0,
- 'sparseInfillLineDistance': int(100 * profile.calculateEdgeWidth() * 1000 / profile.getProfileSettingFloat('fill_density')) if profile.getProfileSettingFloat('fill_density') > 0 else 9999999999,
- 'skirtDistance': int(profile.getProfileSettingFloat('skirt_gap') * 1000),
- 'skirtLineCount': int(profile.getProfileSettingFloat('skirt_line_count')),
+ 'infillOverlap': int(profile.getProfileSettingFloat('fill_overlap')),
'initialSpeedupLayers': int(4),
'initialLayerSpeed': int(profile.getProfileSettingFloat('bottom_layer_speed')),
'printSpeed': int(profile.getProfileSettingFloat('print_speed')),
+ 'infillSpeed': int(profile.getProfileSettingFloat('infill_speed')) if int(profile.getProfileSettingFloat('infill_speed')) > 0 else int(profile.getProfileSettingFloat('print_speed')),
'moveSpeed': int(profile.getProfileSettingFloat('travel_speed')),
- 'fanOnLayerNr': int(profile.getProfileSettingFloat('fan_layer')),
- 'supportAngle': int(-1) if profile.getProfileSetting('support') == 'None' else int(60),
+ 'fanSpeedMin': int(profile.getProfileSettingFloat('fan_speed')) if profile.getProfileSetting('fan_enabled') == 'True' else 0,
+ 'fanSpeedMax': int(profile.getProfileSettingFloat('fan_speed_max')) if profile.getProfileSetting('fan_enabled') == 'True' else 0,
+ 'supportAngle': int(-1) if profile.getProfileSetting('support') == 'None' else int(profile.getProfileSettingFloat('support_angle')),
'supportEverywhere': int(1) if profile.getProfileSetting('support') == 'Everywhere' else int(0),
- 'retractionAmount': int(profile.getProfileSettingFloat('retraction_amount') * 1000),
+ 'supportLineDistance': int(100 * profile.calculateEdgeWidth() * 1000 / profile.getProfileSettingFloat('support_fill_rate')) if profile.getProfileSettingFloat('support_fill_rate') > 0 else -1,
+ 'supportXYDistance': int(1000 * profile.getProfileSettingFloat('support_xy_distance')),
+ 'supportZDistance': int(1000 * profile.getProfileSettingFloat('support_z_distance')),
+ '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),
+ 'retractionAmount': int(profile.getProfileSettingFloat('retraction_amount') * 1000) if profile.getProfileSetting('retraction_enable') == 'True' else 0,
'retractionSpeed': int(profile.getProfileSettingFloat('retraction_speed')),
+ 'retractionMinimalDistance': int(profile.getProfileSettingFloat('retraction_min_travel') * 1000),
+ 'retractionAmountExtruderSwitch': int(profile.getProfileSettingFloat('retraction_dual_amount') * 1000),
+ 'minimalExtrusionBeforeRetraction': int(profile.getProfileSettingFloat('retraction_minimal_extrusion') * 1000),
+ 'enableCombing': 1 if profile.getProfileSetting('retraction_combing') == 'True' else 0,
+ 'multiVolumeOverlap': int(profile.getProfileSettingFloat('overlap_dual') * 1000),
'objectSink': int(profile.getProfileSettingFloat('object_sink') * 1000),
'minimalLayerTime': int(profile.getProfileSettingFloat('cool_min_layer_time')),
'minimalFeedrate': int(profile.getProfileSettingFloat('cool_min_feedrate')),
'coolHeadLift': 1 if profile.getProfileSetting('cool_head_lift') == 'True' else 0,
- 'startCode': profile.getAlterationFileContents('start.gcode'),
- 'endCode': profile.getAlterationFileContents('end.gcode'),
+ 'startCode': profile.getAlterationFileContents('start.gcode', extruderCount),
+ 'endCode': profile.getAlterationFileContents('end.gcode', extruderCount),
+
+ 'extruderOffset[1].X': int(profile.getMachineSettingFloat('extruder_offset_x1') * 1000),
+ 'extruderOffset[1].Y': int(profile.getMachineSettingFloat('extruder_offset_y1') * 1000),
+ 'extruderOffset[2].X': int(profile.getMachineSettingFloat('extruder_offset_x2') * 1000),
+ 'extruderOffset[2].Y': int(profile.getMachineSettingFloat('extruder_offset_y2') * 1000),
+ 'extruderOffset[3].X': int(profile.getMachineSettingFloat('extruder_offset_x3') * 1000),
+ 'extruderOffset[3].Y': int(profile.getMachineSettingFloat('extruder_offset_y3') * 1000),
+ 'fixHorrible': 0,
}
+ fanFullHeight = int(profile.getProfileSettingFloat('fan_full_height') * 1000)
+ settings['fanFullOnLayerNr'] = (fanFullHeight - settings['initialLayerThickness'] - 1) / settings['layerThickness'] + 1
+ if settings['fanFullOnLayerNr'] < 0:
+ settings['fanFullOnLayerNr'] = 0
+
+ if profile.getProfileSettingFloat('fill_density') == 0:
+ settings['sparseInfillLineDistance'] = -1
+ elif profile.getProfileSettingFloat('fill_density') == 100:
+ settings['sparseInfillLineDistance'] = settings['extrusionWidth']
+ #Set the up/down skins height to 10000 if we want a 100% filled object.
+ # This gives better results then normal 100% infill as the sparse and up/down skin have some overlap.
+ settings['downSkinCount'] = 10000
+ settings['upSkinCount'] = 10000
+ else:
+ settings['sparseInfillLineDistance'] = int(100 * profile.calculateEdgeWidth() * 1000 / profile.getProfileSettingFloat('fill_density'))
+ if profile.getProfileSetting('platform_adhesion') == 'Brim':
+ settings['skirtDistance'] = 0
+ settings['skirtLineCount'] = int(profile.getProfileSettingFloat('brim_line_count'))
+ elif profile.getProfileSetting('platform_adhesion') == 'Raft':
+ settings['skirtDistance'] = 0
+ settings['skirtLineCount'] = 0
+ settings['raftMargin'] = int(profile.getProfileSettingFloat('raft_margin') * 1000)
+ settings['raftLineSpacing'] = int(profile.getProfileSettingFloat('raft_line_spacing') * 1000)
+ settings['raftBaseThickness'] = int(profile.getProfileSettingFloat('raft_base_thickness') * 1000)
+ settings['raftBaseLinewidth'] = int(profile.getProfileSettingFloat('raft_base_linewidth') * 1000)
+ settings['raftInterfaceThickness'] = int(profile.getProfileSettingFloat('raft_interface_thickness') * 1000)
+ settings['raftInterfaceLinewidth'] = int(profile.getProfileSettingFloat('raft_interface_linewidth') * 1000)
+ else:
+ settings['skirtDistance'] = int(profile.getProfileSettingFloat('skirt_gap') * 1000)
+ settings['skirtLineCount'] = int(profile.getProfileSettingFloat('skirt_line_count'))
+ settings['skirtMinLength'] = int(profile.getProfileSettingFloat('skirt_minimal_length') * 1000)
+
+ if profile.getProfileSetting('fix_horrible_union_all_type_a') == 'True':
+ settings['fixHorrible'] |= 0x01
+ if profile.getProfileSetting('fix_horrible_union_all_type_b') == 'True':
+ settings['fixHorrible'] |= 0x02
+ if profile.getProfileSetting('fix_horrible_use_open_bits') == 'True':
+ settings['fixHorrible'] |= 0x10
+ if profile.getProfileSetting('fix_horrible_extensive_stitching') == 'True':
+ settings['fixHorrible'] |= 0x04
+
+ if settings['layerThickness'] <= 0:
+ settings['layerThickness'] = 1000
+ if profile.getMachineSetting('gcode_flavor') == 'UltiGCode':
+ settings['gcodeFlavor'] = 1
+ if profile.getProfileSetting('spiralize') == 'True':
+ settings['spiralizeMode'] = 1
+ if profile.getProfileSetting('wipe_tower') == 'True':
+ settings['wipeTowerSize'] = int(math.sqrt(profile.getProfileSettingFloat('wipe_tower_volume') * 1000 * 1000 * 1000 / settings['layerThickness']))
+ if profile.getProfileSetting('ooze_shield') == 'True':
+ settings['enableOozeShield'] = 1
+ return settings
- def _runSliceProcess(self, cmdList):
+ def _runEngineProcess(self, cmdList):
kwargs = {}
if subprocess.mswindows:
su = subprocess.STARTUPINFO()