chiark / gitweb /
Add back the ultimaker platform, and made the platform mesh simpler.
[cura.git] / Cura / slice / cura_sf / skeinforge_application / skeinforge_plugins / craft_plugins / export_plugins / gcode_time_segment.py
1 """
2 This page is in the table of contents.
3 Gcode time segment is an export plugin to convert gcode from float position to number of steps.
4
5 An export plugin is a script in the export_plugins folder which has the getOutput function, the globalIsReplaceable variable and if it's output is not replaceable, the writeOutput function.  It is meant to be run from the export tool.  To ensure that the plugin works on platforms which do not handle file capitalization properly, give the plugin a lower case name.
6
7 The getOutput function of this script takes a gcode text and returns it with the positions converted into number of steps and time.  The writeOutput function of this script takes a gcode text and writes that with the positions converted into number of steps and time.
8
9 ==Settings==
10 ===Add Space Between Words===
11 Default is on.
12
13 When selected, a space will be added between each gcode word.
14
15 ===Offset===
16 ====X Offset====
17 Default is zero.
18
19 Defines the X Offset.
20
21 ====Y Offset====
22 Default is zero.
23
24 Defines the Y Offset.
25
26 ====Z Offset====
27 Default is zero.
28
29 Defines the Z Offset.
30
31 ===Step===
32 ===Extrusion Step===
33 Default is 0.01 mm.
34
35 Defines the radius step length.
36
37 ===Time Step===
38 Default is 1 microsecond(mcs).
39
40 Defines the time step duration.
41
42 ====X Step====
43 Default is 0.1 mm.
44
45 Defines the X axis step length.
46
47 ====Y Step====
48 Default is 0.1 mm.
49
50 Defines the Y axis step length.
51
52 ====Z Step====
53 Default is 0.01 mm.
54
55 Defines the Z axis step length.
56
57 """
58
59
60 from __future__ import absolute_import
61
62 from fabmetheus_utilities import archive
63 from fabmetheus_utilities import gcodec
64 from fabmetheus_utilities import settings
65 from skeinforge_application.skeinforge_utilities import skeinforge_polyfile
66 from skeinforge_application.skeinforge_utilities import skeinforge_profile
67 import cStringIO
68 import sys
69
70
71 __author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
72 __date__ = '$Date: 2008/21/04 $'
73 __license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
74
75
76 # This is true if the output is text and false if it is binary."
77 globalIsReplaceable = True
78
79
80 def getCharacterIntegerString( character, offset, splitLine, step ):
81         "Get a character and integer string."
82         floatValue = getFloatFromCharacterSplitLine(character, splitLine)
83         if floatValue == None:
84                 return None
85         floatValue += offset
86         integerValue = int(round(float(floatValue / step)))
87         return character + str( integerValue )
88
89 def getFloatFromCharacterSplitLine(character, splitLine):
90         "Get the float after the first occurence of the character in the split line."
91         lineFromCharacter = gcodec.getStringFromCharacterSplitLine(character, splitLine)
92         if lineFromCharacter == None:
93                 return None
94         return float(lineFromCharacter)
95
96 def getNewRepository():
97         'Get new repository.'
98         return GcodeTimeSegmentRepository()
99
100 def getOutput(gcodeText, repository=None):
101         'Get the exported version of a gcode file.'
102         if gcodeText == '':
103                 return ''
104         if repository == None:
105                 repository = GcodeTimeSegmentRepository()
106                 settings.getReadRepository(repository)
107         return GcodeTimeSegmentSkein().getCraftedGcode(gcodeText, repository)
108
109 def writeOutput( fileName, gcodeText = ''):
110         "Write the exported version of a gcode file."
111         gcodeText = gcodec.getGcodeFileText(fileName, gcodeText)
112         repository = GcodeTimeSegmentRepository()
113         settings.getReadRepository(repository)
114         output = getOutput(gcodeText, repository)
115         suffixFileName = fileName[ : fileName.rfind('.') ] + '_gcode_time_segment.gcode'
116         archive.writeFileText( suffixFileName, output )
117         print('The converted file is saved as ' + archive.getSummarizedFileName(suffixFileName) )
118
119
120 class GcodeTimeSegmentRepository(object):
121         "A class to handle the export settings."
122         def __init__(self):
123                 "Set the default settings, execute title & settings fileName."
124                 skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.export_plugins.gcode_time.html', self)
125                 self.addSpaceBetweenWords = settings.BooleanSetting().getFromValue('Add Space Between Words', self, True )
126                 self.fileNameInput = settings.FileNameInput().getFromFileName( [ ('Gcode text files', '*.gcode') ], 'Open File to be Converted to Gcode Time', self, '')
127                 self.initialTime = settings.FloatSpin().getFromValue(0.0, 'Initial Time (s)', self, 20.0, 10.0)
128                 settings.LabelSeparator().getFromRepository(self)
129                 settings.LabelDisplay().getFromName('- Offset -', self )
130                 self.xOffset = settings.FloatSpin().getFromValue( - 100.0, 'X Offset (mm)', self, 100.0, 0.0 )
131                 self.yOffset = settings.FloatSpin().getFromValue( -100.0, 'Y Offset (mm)', self, 100.0, 0.0 )
132                 self.zOffset = settings.FloatSpin().getFromValue( - 10.0, 'Z Offset (mm)', self, 10.0, 0.0 )
133                 settings.LabelSeparator().getFromRepository(self)
134                 settings.LabelDisplay().getFromName('- Step -', self )
135                 self.extrusionStep = settings.FloatSpin().getFromValue(0.0, 'Extrusion Step (mm)', self, 0.2, 0.01)
136                 self.timeStep = settings.FloatSpin().getFromValue(0.0, 'Time Step (mcs)', self, 2000.0, 1000.0)
137                 self.xStep = settings.FloatSpin().getFromValue(0.0, 'X Step (mm)', self, 1.0, 0.1)
138                 self.yStep = settings.FloatSpin().getFromValue(0.0, 'Y Step (mm)', self, 1.0, 0.1)
139                 self.zStep = settings.FloatSpin().getFromValue(0.0, 'Z Step (mm)', self, 0.2, 0.01)
140                 settings.LabelSeparator().getFromRepository(self)
141                 self.executeTitle = 'Convert to Gcode Time'
142
143         def execute(self):
144                 "Convert to gcode step button has been clicked."
145                 fileNames = skeinforge_polyfile.getFileOrDirectoryTypesUnmodifiedGcode( self.fileNameInput.value, ['.gcode'], self.fileNameInput.wasCancelled )
146                 for fileName in fileNames:
147                         writeOutput(fileName)
148
149
150 class GcodeTimeSegmentSkein(object):
151         "A class to convert gcode into time segments."
152         def __init__(self):
153                 'Initialize.'
154                 self.feedRateMinute = None
155                 self.isExtruderActive = False
156                 self.oldFeedRateString = None
157                 self.oldLocation = None
158                 self.oldZString = None
159                 self.operatingFlowRate = None
160                 self.output = cStringIO.StringIO()
161
162         def addCharacterInteger(self, character, lineStringIO, offset, splitLine, step):
163                 "Add a character and integer to line string."
164                 characterIntegerString = getCharacterIntegerString(character, offset, splitLine, step)
165                 self.addStringToLine(lineStringIO, characterIntegerString)
166
167         def addLine(self, line):
168                 "Add a line of text and a newline to the output."
169                 self.output.write(line + '\n')
170
171         def addStringToLine( self, lineStringIO, wordString ):
172                 "Add a character and integer to line string."
173                 if wordString == None:
174                         return
175                 if self.repository.addSpaceBetweenWords.value:
176                         lineStringIO.write(' ')
177                 lineStringIO.write( wordString )
178
179         def getCraftedGcode(self, gcodeText, repository):
180                 "Parse gcode text and store the gcode."
181                 self.repository = repository
182                 lines = archive.getTextLines(gcodeText)
183                 for line in lines:
184                         self.parseLine(line)
185                 return self.output.getvalue()
186
187         def parseLine(self, line):
188                 "Parse a gcode line."
189                 splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
190                 firstWord = gcodec.getFirstWord(splitLine)
191                 if len(firstWord) < 1:
192                         return
193                 firstLetter = firstWord[0]
194                 if firstWord == '(<operatingFeedRatePerSecond>':
195                         self.feedRateMinute = 60.0 * float(splitLine[1])
196                 elif firstWord == '(<operatingFlowRate>':
197                         self.operatingFlowRate = float(splitLine[1])
198                         self.flowRate = self.operatingFlowRate
199                 if firstLetter == '(':
200                         return
201                 if firstWord == 'M101':
202                         self.isExtruderActive = True
203                 elif firstWord == 'M103':
204                         self.isExtruderActive = False
205                 elif firstWord == 'M108':
206                         self.flowRate = float(splitLine[1][1 :])
207                 if firstWord != 'G1' and firstWord != 'G2' and firstWord != 'G3':
208                         self.addLine(line)
209                         return
210                 self.feedRateMinute = gcodec.getFeedRateMinute(self.feedRateMinute, splitLine)
211                 lineStringIO = cStringIO.StringIO()
212                 lineStringIO.write(firstWord)
213                 location = gcodec.getLocationFromSplitLine(self.oldLocation, splitLine)
214                 self.addCharacterInteger('X', lineStringIO, self.repository.xOffset.value, splitLine, self.repository.xStep.value )
215                 self.addCharacterInteger('Y', lineStringIO, self.repository.yOffset.value, splitLine, self.repository.yStep.value )
216                 zString = getCharacterIntegerString('Z', self.repository.zOffset.value, splitLine, self.repository.zStep.value )
217                 if zString == None:
218                         zString = self.oldZString
219                 self.addStringToLine(lineStringIO, zString)
220                 duration = self.repository.initialTime.value
221                 if self.oldLocation != None:
222                         distance = abs(location - self.oldLocation)
223                         duration = 60.0 / self.feedRateMinute * distance
224                 extrusionDistance = 0.0
225                 if self.isExtruderActive:
226                         extrusionDistance = self.flowRate * duration
227                 self.addStringToLine(lineStringIO, 'E%s' % int(round(extrusionDistance / self.repository.extrusionStep.value)))
228                 self.addStringToLine(lineStringIO, 'D%s' % int(round(duration * 1000000.0 / self.repository.timeStep.value)))
229                 self.addLine(lineStringIO.getvalue())
230                 self.oldLocation = location
231                 self.oldZString = zString
232
233
234 def main():
235         "Display the export dialog."
236         if len(sys.argv) > 1:
237                 writeOutput(' '.join(sys.argv[1 :]))
238         else:
239                 settings.startMainLoopFromConstructor(getNewRepository())
240
241 if __name__ == "__main__":
242         main()