self.startTime = time.time()
if profile.getPreference('save_profile') == 'True':
profile.saveGlobalProfile(self.filelist[0][: self.filelist[0].rfind('.')] + "_profile.ini")
- cmdList = []
- for filename in self.filelist:
- idx = self.filelist.index(filename)
- #print filename, idx
- if idx > 0:
- profile.setTempOverride('fan_enabled', 'False')
- profile.setTempOverride('skirt_line_count', '0')
- profile.setTempOverride('object_center_x', profile.getPreferenceFloat('machine_width') / 2 - profile.getPreferenceFloat('extruder_offset_x%d' % (idx)))
- profile.setTempOverride('object_center_y', profile.getPreferenceFloat('machine_depth') / 2 - profile.getPreferenceFloat('extruder_offset_y%d' % (idx)))
- profile.setTempOverride('alternative_center', self.filelist[0])
- if len(self.filelist) > 1:
- profile.setTempOverride('add_start_end_gcode', 'False')
- profile.setTempOverride('gcode_extension', 'multi_extrude_tmp')
- cmdList.append(sliceRun.getSliceCommand(filename))
- profile.resetTempOverride()
+ center = profile.getMachineCenterCoords()
+ cmdList = [sliceRun.getSliceCommand(sliceRun.getExportFilename(self.filelist[0]), ['|'.join(self.filelist)], [center])]
self.thread = WorkerThread(self, filelist, cmdList)
def OnAbort(self, e):
line = p.stdout.readline()
self.progressLog = []
maxValue = 1
- while(len(line) > 0):
+ starttime = time.time()
+ while len(line) > 0:
line = line.rstrip()
if line[0:9] == "Progress[" and line[-1:] == "]":
progress = line[9:-1].split(":")
maxValue = int(progress[2])
wx.CallAfter(self.notifyWindow.SetProgress, progress[0], int(progress[1]), maxValue)
else:
- self.progressLog.append(line)
+ self.progressLog.append("%0.2f: %s" % (time.time() - starttime, line))
wx.CallAfter(self.notifyWindow.statusText.SetLabel, line)
if self.notifyWindow.abort:
p.terminate()
return
line = p.stdout.readline()
line = p.stderr.readline()
- while(len(line) > 0):
+ while len(line) > 0:
line = line.rstrip()
self.progressLog.append(line)
line = p.stderr.readline()
self.returnCode = p.wait()
self.fileIdx += 1
if self.fileIdx == len(self.cmdList):
- if len(self.filelist) > 1:
- self._stitchMultiExtruder()
gcodeFilename = sliceRun.getExportFilename(self.filelist[0])
gcodefile = open(gcodeFilename, "a")
for logLine in self.progressLog:
if logLine.startswith('Model error('):
gcodefile.write(';%s\n' % (logLine))
gcodefile.close()
- wx.CallAfter(self.notifyWindow.statusText.SetLabel, "Running plugins")
- ret = profile.runPostProcessingPlugins(gcodeFilename)
- if ret != None:
- self.progressLog.append(ret)
self.gcode = gcodeInterpreter.gcode()
self.gcode.load(gcodeFilename)
profile.replaceGCodeTags(gcodeFilename, self.gcode)
wx.CallAfter(self.notifyWindow.OnSliceDone, self)
else:
self.run()
-
- def _stitchMultiExtruder(self):
- files = []
- resultFile = open(sliceRun.getExportFilename(self.filelist[0]), "w")
- resultFile.write(';TYPE:CUSTOM\n')
- resultFile.write(profile.getAlterationFileContents('start.gcode'))
- for filename in self.filelist:
- if os.path.isfile(sliceRun.getExportFilename(filename, 'multi_extrude_tmp')):
- files.append(open(sliceRun.getExportFilename(filename, 'multi_extrude_tmp'), "r"))
- else:
- return
-
- currentExtruder = 0
- resultFile.write('T%d\n' % (currentExtruder))
- layerNr = -1
- hasLine = True
- filesOrder = files[:]
- while hasLine:
- hasLine = False
- filesOrder.reverse()
- for f in filesOrder:
- layerHasLine = False
- for line in f:
- hasLine = True
- if line.startswith(';LAYER:'):
- break
- if 'Z' in line:
- lastZ = float(re.search('Z([^\s]+)', line).group(1))
- if not layerHasLine:
- nextExtruder = files.index(f)
- resultFile.write(';LAYER:%d\n' % (layerNr))
- resultFile.write(';EXTRUDER:%d\n' % (nextExtruder))
- if nextExtruder != currentExtruder:
- resultFile.write(';TYPE:CUSTOM\n')
- profile.setTempOverride('extruder', nextExtruder)
- resultFile.write(profile.getAlterationFileContents('switchExtruder.gcode') + '\n')
- profile.resetTempOverride()
- currentExtruder = nextExtruder
- layerHasLine = True
- resultFile.write(line)
- layerNr += 1
- for f in files:
- f.close()
- for filename in self.filelist:
- os.remove(sliceRun.getExportFilename(filename, 'multi_extrude_tmp'))
- resultFile.write(';TYPE:CUSTOM\n')
- resultFile.write(profile.getAlterationFileContents('end.gcode'))
- resultFile.close()
class LogWindow(wx.Frame):
def __init__(self, logText):
def OnSlice(self, e):
sliceCmdList = []
+ center = profile.getMachineCenterCoords()
for filename in self.list:
- sliceCmdList.append(sliceRun.getSliceCommand(filename))
+ sliceCmdList.append(sliceRun.getSliceCommand(sliceRun.getExportFilename(filename), [filename], [center]))
bspw = BatchSliceProgressWindow(self.list[:], sliceCmdList)
bspw.Centre()
bspw.Show(True)
def writeFileText(fileName, fileText, writeMode='w+'):
'Write a text to a file.'
- try:
- file = open(fileName, writeMode)
- file.write(fileText)
- file.close()
- except IOError:
- print('The file ' + fileName + ' can not be written to.')
+ file = open(fileName, writeMode)
+ file.write(fileText)
+ file.close()
import math
from Cura.util import profile
-from Cura.cura_sf.fabmetheus_utilities import archive
+from Cura.slice.cura_sf.fabmetheus_utilities import archive
def DEFSET(setting):
return setting.value
'Retraction_Distance_millimeters': lambda setting: profile.getProfileSettingFloat('retraction_amount') if profile.getProfileSetting('retraction_enable') == 'True' else 0,
'Restart_Extra_Distance_millimeters': storedSettingFloat('retraction_extra'),
},'alteration': {
- 'Activate_Alteration': storedSetting('add_start_end_gcode'),
+ 'Activate_Alteration': "False",
'Name_of_End_File': "end.gcode",
'Name_of_Start_File': "start.gcode",
'Remove_Redundant_Mcode': "True",
def addFromUpperLowerFile(self, fileName):
"Add lines of text from the fileName or the lowercase fileName, if there is no file by the original fileName in the directory."
- alterationFileLines = map(lambda l: l.replace('?filename?', self.fileName), settings.getAlterationFileLines(fileName))
+ alterationFileLines = map(lambda l: l.replace('?filename?', self.fileName.encode('ascii', 'replace')), settings.getAlterationFileLines(fileName))
self.distanceFeedRate.addLinesSetAbsoluteDistanceMode(alterationFileLines)
def getCraftedGcode(self, gcodeText, repository, fileName):
return
archive.writeFileText(outputTo, text)
-def writeOutput(fileName, shouldAnalyze=True):
+def getOutput(fileName):
'Export a gcode linear move file.'
if fileName == '':
return None
settings.getReadRepository(repository)
startTime = time.time()
print('File ' + archive.getSummarizedFileName(fileName.encode('ascii', 'replace')) + ' is being chain exported.')
- fileNameSuffix = fileName[: fileName.rfind('.')]
- if repository.addExportSuffix.value:
- fileNameSuffix += '_export'
gcodeText = gcodec.getGcodeFileText(fileName, '')
procedures = skeinforge_craft.getProcedures('export', gcodeText)
gcodeText = skeinforge_craft.getChainTextFromProcedures(fileName, procedures[: -1], gcodeText)
if gcodeText == '':
return None
- if repository.addProfileExtension.value:
- fileNameSuffix += '.' + getFirstValue(gcodeText, '(<profileName>')
- if repository.addDescriptiveExtension.value:
- fileNameSuffix += getDescriptiveExtension(gcodeText)
- if repository.addTimestampExtension.value:
- fileNameSuffix += '.' + getFirstValue(gcodeText, '(<timeStampPreface>')
- fileNameSuffix += '.' + repository.fileExtension.value
fileNamePenultimate = fileName[: fileName.rfind('.')] + '_penultimate.gcode'
- filePenultimateWritten = False
if repository.savePenultimateGcode.value:
archive.writeFileText(fileNamePenultimate, gcodeText)
- filePenultimateWritten = True
print('The penultimate file is saved as ' + archive.getSummarizedFileName(fileNamePenultimate))
exportGcode = getCraftedTextFromText(gcodeText, repository)
- window = None
- if shouldAnalyze and repository.analyzeGcode.value:
- window = skeinforge_analyze.writeOutput(fileName, fileNamePenultimate, fileNameSuffix, filePenultimateWritten, gcodeText)
replaceableExportGcode = None
selectedPluginModule = getSelectedPluginModule(repository.exportPlugins)
- if selectedPluginModule == None:
+ if selectedPluginModule is None:
replaceableExportGcode = exportGcode
else:
if selectedPluginModule.globalIsReplaceable:
replaceableExportGcode = selectedPluginModule.getOutput(exportGcode)
- else:
- selectedPluginModule.writeOutput(fileNameSuffix, exportGcode)
- if replaceableExportGcode != None:
+ #else:
+ # selectedPluginModule.writeOutput(outputFilename, exportGcode)
+ if replaceableExportGcode is not None:
replaceableExportGcode = getReplaceableExportGcode(repository.nameOfReplaceFile.value, replaceableExportGcode)
- archive.writeFileText( fileNameSuffix, replaceableExportGcode )
- print('The exported file is saved as ' + archive.getSummarizedFileName(fileNameSuffix))
if repository.alsoSendOutputTo.value != '':
if replaceableExportGcode == None:
replaceableExportGcode = selectedPluginModule.getOutput(exportGcode)
sendOutputTo(repository.alsoSendOutputTo.value, replaceableExportGcode)
print('It took %s to export the file.' % euclidean.getDurationString(time.time() - startTime))
- return window
-
+ return replaceableExportGcode
class ExportRepository(object):
'A class to handle the export settings.'
self.fileNameInput = settings.FileNameInput().getFromFileName( fabmetheus_interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File for Export', self, '')
self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Export')
self.activateExport = settings.BooleanSetting().getFromValue('Activate Export', self, True)
- self.addDescriptiveExtension = settings.BooleanSetting().getFromValue('Add Descriptive Extension', self, False)
- self.addExportSuffix = settings.BooleanSetting().getFromValue('Add Export Suffix', self, True)
- self.addProfileExtension = settings.BooleanSetting().getFromValue('Add Profile Extension', self, False)
- self.addTimestampExtension = settings.BooleanSetting().getFromValue('Add Timestamp Extension', self, False)
self.alsoSendOutputTo = settings.StringSetting().getFromValue('Also Send Output To:', self, '')
self.analyzeGcode = settings.BooleanSetting().getFromValue('Analyze Gcode', self, True)
self.commentChoice = settings.MenuButtonDisplay().getFromName('Comment Choice:', self)
'object_center_x': '-1',
'object_center_y': '-1',
- 'add_start_end_gcode': 'True',
'gcode_extension': 'gcode',
'alternative_center': '',
'clear_z': '0.0',
solidThickness = getProfileSettingFloat('solid_layer_thickness')
return int(math.ceil(solidThickness / layerHeight - 0.0001))
+def getMachineCenterCoords():
+ return (getPreferenceFloat('machine_width') / 2, getPreferenceFloat('machine_depth') / 2)
+
#########################################################
## Alteration file functions
#########################################################
clearTempOverride('extruder')
else:
alterationContents = ''
- return unicode(prefix + re.sub("(.)\{([^\}]*)\}", replaceTagMatch, alterationContents).rstrip() + '\n' + postfix).strip().encode('utf-8')
+ return unicode(prefix + re.sub("(.)\{([^\}]*)\}", replaceTagMatch, alterationContents).rstrip() + '\n' + postfix).strip().encode('utf-8') + '\n'
###### PLUGIN #####
import subprocess
import sys
-if not hasattr(sys, 'frozen'):
- cura_sf_path = os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), "../cura_sf/"))
- if cura_sf_path not in sys.path:
- sys.path.append(cura_sf_path)
- from Cura.cura_sf.skeinforge_application.skeinforge_utilities import skeinforge_craft
-
from Cura.util import resources
from Cura.util import profile
pypyExe = os.path.join(p, exeName)
if os.path.exists(pypyExe):
return pypyExe
- return False
-
-def getSlic3rExe():
- "Return the path to the pypy executable if we can find it. Else return False"
- if platform.system() == "Windows":
- exeName = "slic3r.exe"
- slic3rExe = os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../Slic3r/bin/slic3r.exe"));
- else:
- exeName = "slic3r"
- slic3rExe = os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../Slic3r/bin/slic3r"));
- if os.path.exists(slic3rExe):
- return slic3rExe
-
- path = os.environ['PATH']
- paths = path.split(os.pathsep)
- for p in paths:
- slic3rExe = os.path.join(p, exeName)
- if os.path.exists(slic3rExe):
- return slic3rExe
- return False
-
-def runSlice(fileNames):
- "Run the slicer on the files. If we are running with PyPy then just do the slicing action. If we are running as Python, try to find pypy."
- pypyExe = getPyPyExe()
- for fileName in fileNames:
- if fileName.startswith("#UTF8#"):
- fileName = unicode(fileName[6:], "utf-8")
- if platform.python_implementation() == "PyPy":
- skeinforge_craft.writeOutput(fileName)
- elif pypyExe == False:
- if not hasattr(sys, 'frozen'):
- print("************************************************")
- print("* Failed to find pypy, so slicing with python! *")
- print("************************************************")
- skeinforge_craft.writeOutput(fileName)
- print("************************************************")
- print("* Failed to find pypy, so sliced with python! *")
- print("************************************************")
- else:
- print("******************************************************************")
- print("* Failed to find pypy, we need pypy to slice with a frozen build *")
- print("* Place pypy in the same directory as Cura so Cura can find it. *")
- print("******************************************************************")
- sys.exit(1)
- else:
- subprocess.call(getSliceCommand(fileName))
+ return None
def getExportFilename(filename, ext = "gcode"):
return "%s.%s" % (filename[: filename.rfind('.')], ext)
filename = filename[: filename.rfind('.')]
return filename[:8] + ext[:2]
-def getSliceCommand(filename):
- if profile.getPreference('slicer').startswith('Slic3r') and getSlic3rExe() != False:
- slic3rExe = getSlic3rExe()
- if slic3rExe == False:
- return False
- cmd = [slic3rExe,
- '--output-filename-format', '[input_filename_base].gcode',
- '--nozzle-diameter', str(profile.calculateEdgeWidth()),
- '--print-center', '%s,%s' % (profile.getPreferenceFloat('machine_width') / 2, profile.getPreferenceFloat('machine_depth') / 2),
- '--z-offset', '0',
- '--gcode-flavor', 'reprap',
- '--gcode-comments',
- '--filament-diameter', profile.getProfileSetting('filament_diameter'),
- '--extrusion-multiplier', str(1.0 / float(profile.getProfileSetting('filament_density'))),
- '--temperature', profile.getProfileSetting('print_temperature'),
- '--travel-speed', profile.getProfileSetting('travel_speed'),
- '--perimeter-speed', profile.getProfileSetting('print_speed'),
- '--small-perimeter-speed', profile.getProfileSetting('print_speed'),
- '--infill-speed', profile.getProfileSetting('print_speed'),
- '--solid-infill-speed', profile.getProfileSetting('print_speed'),
- '--bridge-speed', profile.getProfileSetting('print_speed'),
- '--bottom-layer-speed-ratio', str(float(profile.getProfileSetting('bottom_layer_speed')) / float(profile.getProfileSetting('print_speed'))),
- '--layer-height', profile.getProfileSetting('layer_height'),
- '--first-layer-height-ratio', '1.0',
- '--infill-every-layers', '1',
- '--perimeters', str(profile.calculateLineCount()),
- '--solid-layers', str(profile.calculateSolidLayerCount()),
- '--fill-density', str(float(profile.getProfileSetting('fill_density'))/100),
- '--fill-angle', '45',
- '--fill-pattern', 'rectilinear', #rectilinear line concentric hilbertcurve archimedeanchords octagramspiral
- '--solid-fill-pattern', 'rectilinear',
- '--start-gcode', profile.getAlterationFilePath('start.gcode'),
- '--end-gcode', profile.getAlterationFilePath('end.gcode'),
- '--retract-length', profile.getProfileSetting('retraction_amount'),
- '--retract-speed', str(int(float(profile.getProfileSetting('retraction_speed')))),
- '--retract-restart-extra', profile.getProfileSetting('retraction_extra'),
- '--retract-before-travel', profile.getProfileSetting('retraction_min_travel'),
- '--retract-lift', '0',
- '--slowdown-below-layer-time', profile.getProfileSetting('cool_min_layer_time'),
- '--min-print-speed', profile.getProfileSetting('cool_min_feedrate'),
- '--skirts', profile.getProfileSetting('skirt_line_count'),
- '--skirt-distance', str(int(float(profile.getProfileSetting('skirt_gap')))),
- '--skirt-height', '1',
- '--scale', profile.getProfileSetting('model_scale'),
- '--rotate', profile.getProfileSetting('model_rotate_base'),
- '--duplicate-x', profile.getProfileSetting('model_multiply_x'),
- '--duplicate-y', profile.getProfileSetting('model_multiply_y'),
- '--duplicate-distance', '10']
- if profile.getProfileSetting('support') != 'None':
- cmd.extend(['--support-material'])
- cmd.extend([filename])
- return cmd
- else:
- pypyExe = getPyPyExe()
- if pypyExe == False:
- pypyExe = sys.executable
-
- #In case we have a frozen exe, then argv[0] points to the executable, but we want to give pypy a real script file.
- #if hasattr(sys, 'frozen'):
- # mainScriptFile = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), "../..", "cura_sf.zip"))
- #else:
- # mainScriptFile = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", os.path.split(sys.argv[0])[1]))
- cmd = [pypyExe, '-m', 'Cura.cura', '-p', profile.getGlobalProfileString(), '-s']
- if platform.system() == "Windows":
- try:
- cmd.append(str(filename))
- except UnicodeEncodeError:
- cmd.append("#UTF8#" + filename.encode("utf-8"))
- else:
- cmd.append(filename)
- return cmd
+def getSliceCommand(outputfilename, filenames, positions):
+ pypyExe = getPyPyExe()
+ if pypyExe is None:
+ pypyExe = sys.executable
+ cmd = [pypyExe, '-m', 'Cura.slice', '-p', profile.getGlobalProfileString(), '-o']
+ try:
+ cmd.append(str(outputfilename))
+ except UnicodeEncodeError:
+ cmd.append("#UTF8#" + outputfilename.encode("utf-8"))
+ for idx in xrange(0, len(filenames)):
+ filename = filenames[idx]
+ position = positions[idx]
+ cmd.append("%f,%f" % (position[0], position[1]))
+ try:
+ cmd.append(str(filename))
+ except UnicodeEncodeError:
+ cmd.append("#UTF8#" + filename.encode("utf-8"))
+ return cmd
def startSliceCommandProcess(cmdList):
kwargs = {}