chiark / gitweb /
4a7e7562b4c264cb9b0385fb17b94aad4b4602b0
[cura.git] / Cura / 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 import __init__
62 from fabmetheus_utilities import archive
63 from fabmetheus_utilities import gcodec
64 from fabmetheus_utilities import settings
65 from fabmetheus_utilities.fabmetheus_tools import fabmetheus_interpret
66 from skeinforge_application.skeinforge_utilities import skeinforge_polyfile
67 from skeinforge_application.skeinforge_utilities import skeinforge_profile
68 from struct import Struct
69 import cStringIO
70 import os
71 import sys
72
73
74 __author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
75 __date__ = '$Date: 2008/21/04 $'
76 __license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
77
78
79 # This is true if the output is text and false if it is binary."
80 globalIsReplaceable = True
81
82
83 def getCharacterIntegerString( character, offset, splitLine, step ):
84         "Get a character and integer string."
85         floatValue = getFloatFromCharacterSplitLine(character, splitLine)
86         if floatValue == None:
87                 return None
88         floatValue += offset
89         integerValue = int(round(float(floatValue / step)))
90         return character + str( integerValue )
91
92 def getFloatFromCharacterSplitLine(character, splitLine):
93         "Get the float after the first occurence of the character in the split line."
94         lineFromCharacter = gcodec.getStringFromCharacterSplitLine(character, splitLine)
95         if lineFromCharacter == None:
96                 return None
97         return float(lineFromCharacter)
98
99 def getNewRepository():
100         'Get new repository.'
101         return GcodeTimeSegmentRepository()
102
103 def getOutput(gcodeText, repository=None):
104         'Get the exported version of a gcode file.'
105         if gcodeText == '':
106                 return ''
107         if repository == None:
108                 repository = GcodeTimeSegmentRepository()
109                 settings.getReadRepository(repository)
110         return GcodeTimeSegmentSkein().getCraftedGcode(gcodeText, repository)
111
112 def writeOutput( fileName, gcodeText = ''):
113         "Write the exported version of a gcode file."
114         gcodeText = gcodec.getGcodeFileText(fileName, gcodeText)
115         repository = GcodeTimeSegmentRepository()
116         settings.getReadRepository(repository)
117         output = getOutput(gcodeText, repository)
118         suffixFileName = fileName[ : fileName.rfind('.') ] + '_gcode_time_segment.gcode'
119         archive.writeFileText( suffixFileName, output )
120         print('The converted file is saved as ' + archive.getSummarizedFileName(suffixFileName) )
121
122
123 class GcodeTimeSegmentRepository:
124         "A class to handle the export settings."
125         def __init__(self):
126                 "Set the default settings, execute title & settings fileName."
127                 skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.export_plugins.gcode_time.html', self)
128                 self.addSpaceBetweenWords = settings.BooleanSetting().getFromValue('Add Space Between Words', self, True )
129                 self.fileNameInput = settings.FileNameInput().getFromFileName( [ ('Gcode text files', '*.gcode') ], 'Open File to be Converted to Gcode Time', self, '')
130                 self.initialTime = settings.FloatSpin().getFromValue(0.0, 'Initial Time (s)', self, 20.0, 10.0)
131                 settings.LabelSeparator().getFromRepository(self)
132                 settings.LabelDisplay().getFromName('- Offset -', self )
133                 self.xOffset = settings.FloatSpin().getFromValue( - 100.0, 'X Offset (mm)', self, 100.0, 0.0 )
134                 self.yOffset = settings.FloatSpin().getFromValue( -100.0, 'Y Offset (mm)', self, 100.0, 0.0 )
135                 self.zOffset = settings.FloatSpin().getFromValue( - 10.0, 'Z Offset (mm)', self, 10.0, 0.0 )
136                 settings.LabelSeparator().getFromRepository(self)
137                 settings.LabelDisplay().getFromName('- Step -', self )
138                 self.extrusionStep = settings.FloatSpin().getFromValue(0.0, 'Extrusion Step (mm)', self, 0.2, 0.01)
139                 self.timeStep = settings.FloatSpin().getFromValue(0.0, 'Time Step (mcs)', self, 2000.0, 1000.0)
140                 self.xStep = settings.FloatSpin().getFromValue(0.0, 'X Step (mm)', self, 1.0, 0.1)
141                 self.yStep = settings.FloatSpin().getFromValue(0.0, 'Y Step (mm)', self, 1.0, 0.1)
142                 self.zStep = settings.FloatSpin().getFromValue(0.0, 'Z Step (mm)', self, 0.2, 0.01)
143                 settings.LabelSeparator().getFromRepository(self)
144                 self.executeTitle = 'Convert to Gcode Time'
145
146         def execute(self):
147                 "Convert to gcode step button has been clicked."
148                 fileNames = skeinforge_polyfile.getFileOrDirectoryTypesUnmodifiedGcode( self.fileNameInput.value, ['.gcode'], self.fileNameInput.wasCancelled )
149                 for fileName in fileNames:
150                         writeOutput(fileName)
151
152
153 class GcodeTimeSegmentSkein:
154         "A class to convert gcode into time segments."
155         def __init__(self):
156                 'Initialize.'
157                 self.feedRateMinute = None
158                 self.isExtruderActive = False
159                 self.oldFeedRateString = None
160                 self.oldLocation = None
161                 self.oldZString = None
162                 self.operatingFlowRate = None
163                 self.output = cStringIO.StringIO()
164
165         def addCharacterInteger(self, character, lineStringIO, offset, splitLine, step):
166                 "Add a character and integer to line string."
167                 characterIntegerString = getCharacterIntegerString(character, offset, splitLine, step)
168                 self.addStringToLine(lineStringIO, characterIntegerString)
169
170         def addLine(self, line):
171                 "Add a line of text and a newline to the output."
172                 self.output.write(line + '\n')
173
174         def addStringToLine( self, lineStringIO, wordString ):
175                 "Add a character and integer to line string."
176                 if wordString == None:
177                         return
178                 if self.repository.addSpaceBetweenWords.value:
179                         lineStringIO.write(' ')
180                 lineStringIO.write( wordString )
181
182         def getCraftedGcode(self, gcodeText, repository):
183                 "Parse gcode text and store the gcode."
184                 self.repository = repository
185                 lines = archive.getTextLines(gcodeText)
186                 for line in lines:
187                         self.parseLine(line)
188                 return self.output.getvalue()
189
190         def parseLine(self, line):
191                 "Parse a gcode line."
192                 splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
193                 firstWord = gcodec.getFirstWord(splitLine)
194                 if len(firstWord) < 1:
195                         return
196                 firstLetter = firstWord[0]
197                 if firstWord == '(<operatingFeedRatePerSecond>':
198                         self.feedRateMinute = 60.0 * float(splitLine[1])
199                 elif firstWord == '(<operatingFlowRate>':
200                         self.operatingFlowRate = float(splitLine[1])
201                         self.flowRate = self.operatingFlowRate
202                 if firstLetter == '(':
203                         return
204                 if firstWord == 'M101':
205                         self.isExtruderActive = True
206                 elif firstWord == 'M103':
207                         self.isExtruderActive = False
208                 elif firstWord == 'M108':
209                         self.flowRate = float(splitLine[1][1 :])
210                 if firstWord != 'G1' and firstWord != 'G2' and firstWord != 'G3':
211                         self.addLine(line)
212                         return
213                 self.feedRateMinute = gcodec.getFeedRateMinute(self.feedRateMinute, splitLine)
214                 lineStringIO = cStringIO.StringIO()
215                 lineStringIO.write(firstWord)
216                 location = gcodec.getLocationFromSplitLine(self.oldLocation, splitLine)
217                 self.addCharacterInteger('X', lineStringIO, self.repository.xOffset.value, splitLine, self.repository.xStep.value )
218                 self.addCharacterInteger('Y', lineStringIO, self.repository.yOffset.value, splitLine, self.repository.yStep.value )
219                 zString = getCharacterIntegerString('Z', self.repository.zOffset.value, splitLine, self.repository.zStep.value )
220                 if zString == None:
221                         zString = self.oldZString
222                 self.addStringToLine(lineStringIO, zString)
223                 duration = self.repository.initialTime.value
224                 if self.oldLocation != None:
225                         distance = abs(location - self.oldLocation)
226                         duration = 60.0 / self.feedRateMinute * distance
227                 extrusionDistance = 0.0
228                 if self.isExtruderActive:
229                         extrusionDistance = self.flowRate * duration
230                 self.addStringToLine(lineStringIO, 'E%s' % int(round(extrusionDistance / self.repository.extrusionStep.value)))
231                 self.addStringToLine(lineStringIO, 'D%s' % int(round(duration * 1000000.0 / self.repository.timeStep.value)))
232                 self.addLine(lineStringIO.getvalue())
233                 self.oldLocation = location
234                 self.oldZString = zString
235
236
237 def main():
238         "Display the export dialog."
239         if len(sys.argv) > 1:
240                 writeOutput(' '.join(sys.argv[1 :]))
241         else:
242                 settings.startMainLoopFromConstructor(getNewRepository())
243
244 if __name__ == "__main__":
245         main()