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 / oozebane.py
1 """
2 This page is in the table of contents.
3 Oozebane is a script to turn off the extruder before the end of a thread and turn it on before the beginning.
4
5 The oozebane manual page is at:
6 http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Oozebane
7
8 After oozebane turns the extruder on, it slows the feed rate down where the thread starts.  Then it speeds it up in steps so in theory the thread will remain at roughly the same thickness from the beginning.
9
10 ==Operation==
11 The default 'Activate Oozebane' checkbox is on.  When it is on, the functions described below will work, when it is off, the functions will not be called.
12
13 ==Settings==
14 ===After Startup Distance===
15 Default is 1.2.
16
17 When oozebane reaches the point where the extruder would of turned on, it slows down so that the thread will be thick at that point.  Afterwards it speeds the extruder back up to operating speed.  The speed up distance is the "After Startup Distance".
18
19 ===Early Shutdown Distance===
20 Default is 1.2.
21
22 Defines the distance before the end of the thread that the extruder will be turned off.  It is the most important oozebane setting.  A higher distance means the extruder will turn off sooner and the end of the line will be thinner.
23
24 ===Early Startup Maximum Distance===
25 Default is 1.2.
26
27 Defines the maximum distance before the thread starts that the extruder will be turned on
28
29 ===Early Startup Distance Constant===
30 Default is twenty.
31
32 The longer the extruder has been off, the earlier the extruder will turn back on, the ratio is one minus one over e to the power of the distance the extruder has been off over the "Early Startup Distance Constant".
33
34 ===First Early Startup Distance===
35 Default is twenty five.
36
37 Defines the distance before the first thread starts that the extruder will be turned off.  This value should be high because, according to Marius, the extruder takes a second or two to extrude when starting for the first time.
38
39 ===Minimum Distance for Early Shutdown===
40 Default is zero.
41
42 Defines the minimum distance that the extruder has to be off after the thread end for the early shutdown feature to activate.
43
44 ===Minimum Distance for Early Startup===
45 Default is zero.
46
47 Defines the minimum distance that the extruder has to be off before the thread begins for the early start up feature to activate.
48
49 ===Slowdown Startup Steps===
50 Default is three.
51
52 When oozebane turns the extruder off, it slows the feed rate down in steps so in theory the thread will remain at roughly the same thickness until the end.  The "Slowdown Startup Steps" setting is the number of steps, the more steps the smaller the size of the step that the feed rate will be decreased and the larger the size of the resulting gcode file.
53
54 ==Examples==
55 The following examples oozebane the file Screw Holder Bottom.stl.  The examples are run in a terminal in the folder which contains Screw Holder Bottom.stl and oozebane.py.
56
57 > python oozebane.py
58 This brings up the oozebane dialog.
59
60 > python oozebane.py Screw Holder Bottom.stl
61 The oozebane tool is parsing the file:
62 Screw Holder Bottom.stl
63 ..
64 The oozebane tool has created the file:
65 .. Screw Holder Bottom_oozebane.gcode
66
67 """
68
69 from __future__ import absolute_import
70
71 from fabmetheus_utilities.fabmetheus_tools import fabmetheus_interpret
72 from fabmetheus_utilities import archive
73 from fabmetheus_utilities import gcodec
74 from fabmetheus_utilities import settings
75 from skeinforge_application.skeinforge_utilities import skeinforge_craft
76 from skeinforge_application.skeinforge_utilities import skeinforge_polyfile
77 from skeinforge_application.skeinforge_utilities import skeinforge_profile
78 import math
79 import sys
80
81
82 __author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
83 __date__ = '$Date: 2008/21/04 $'
84 __license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
85
86
87 def getCraftedText( fileName, text, oozebaneRepository = None ):
88         "Oozebane a gcode linear move file or text."
89         return getCraftedTextFromText( archive.getTextIfEmpty(fileName, text), oozebaneRepository )
90
91 def getCraftedTextFromText( gcodeText, oozebaneRepository = None ):
92         "Oozebane a gcode linear move text."
93         if gcodec.isProcedureDoneOrFileIsEmpty( gcodeText, 'oozebane'):
94                 return gcodeText
95         if oozebaneRepository == None:
96                 oozebaneRepository = settings.getReadRepository( OozebaneRepository() )
97         if not oozebaneRepository.activateOozebane.value:
98                 return gcodeText
99         return OozebaneSkein().getCraftedGcode( gcodeText, oozebaneRepository )
100
101 def getNewRepository():
102         'Get new repository.'
103         return OozebaneRepository()
104
105 def writeOutput(fileName, shouldAnalyze=True):
106         "Oozebane a gcode linear move file."
107         skeinforge_craft.writeChainTextWithNounMessage(fileName, 'oozebane', shouldAnalyze)
108
109
110 class OozebaneRepository(object):
111         "A class to handle the oozebane settings."
112         def __init__(self):
113                 "Set the default settings, execute title & settings fileName."
114                 skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.oozebane.html', self )
115                 self.fileNameInput = settings.FileNameInput().getFromFileName( fabmetheus_interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File for Oozebane', self, '')
116                 self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Oozebane')
117                 self.activateOozebane = settings.BooleanSetting().getFromValue('Activate Oozebane', self, False )
118                 self.afterStartupDistance = settings.FloatSpin().getFromValue( 0.7, 'After Startup Distance (millimeters):', self, 1.7, 1.2 )
119                 self.earlyShutdownDistance = settings.FloatSpin().getFromValue( 0.7, 'Early Shutdown Distance (millimeters):', self, 1.7, 1.2 )
120                 self.earlyStartupDistanceConstant = settings.FloatSpin().getFromValue( 10.0, 'Early Startup Distance Constant (millimeters):', self, 30.0, 20.0 )
121                 self.earlyStartupMaximumDistance = settings.FloatSpin().getFromValue( 0.7, 'Early Startup Maximum Distance (millimeters):', self, 1.7, 1.2 )
122                 self.firstEarlyStartupDistance = settings.FloatSpin().getFromValue( 5.0, 'First Early Startup Distance (millimeters):', self, 45.0, 25.0 )
123                 self.minimumDistanceForEarlyStartup = settings.FloatSpin().getFromValue( 0.0, 'Minimum Distance for Early Startup (millimeters):', self, 10.0, 0.0 )
124                 self.minimumDistanceForEarlyShutdown = settings.FloatSpin().getFromValue( 0.0, 'Minimum Distance for Early Shutdown (millimeters):', self, 10.0, 0.0 )
125                 self.slowdownStartupSteps = settings.IntSpin().getFromValue( 2, 'Slowdown Startup Steps (positive integer):', self, 5, 3 )
126                 self.executeTitle = 'Oozebane'
127
128         def execute(self):
129                 "Oozebane button has been clicked."
130                 fileNames = skeinforge_polyfile.getFileOrDirectoryTypesUnmodifiedGcode(self.fileNameInput.value, fabmetheus_interpret.getImportPluginFileNames(), self.fileNameInput.wasCancelled)
131                 for fileName in fileNames:
132                         writeOutput(fileName)
133
134
135 class OozebaneSkein(object):
136         "A class to oozebane a skein of extrusions."
137         def __init__(self):
138                 self.distanceFeedRate = gcodec.DistanceFeedRate()
139                 self.distanceFromThreadEndToThreadBeginning = None
140                 self.earlyStartupDistance = None
141                 self.extruderInactiveLongEnough = True
142                 self.feedRateMinute = 961.0
143                 self.isExtruderActive = False
144                 self.isFirstExtrusion = True
145                 self.isShutdownEarly = False
146                 self.isStartupEarly = False
147                 self.lineIndex = 0
148                 self.lines = None
149                 self.oldLocation = None
150                 self.operatingFeedRateMinute = 959.0
151                 self.shutdownStepIndex = 999999999
152                 self.startupStepIndex = 999999999
153
154         def addAfterStartupLine( self, splitLine ):
155                 "Add the after startup lines."
156                 distanceAfterThreadBeginning = self.getDistanceAfterThreadBeginning()
157                 location = gcodec.getLocationFromSplitLine(self.oldLocation, splitLine)
158                 segment = self.oldLocation - location
159                 segmentLength = segment.magnitude()
160                 distanceBack = distanceAfterThreadBeginning - self.afterStartupDistances[ self.startupStepIndex ]
161                 if segmentLength > 0.0:
162                         locationBack = location + segment * distanceBack / segmentLength
163                         feedRate = self.operatingFeedRateMinute * self.afterStartupFlowRates[ self.startupStepIndex ]
164                         if not self.isCloseToEither( locationBack, location, self.oldLocation ):
165                                 self.distanceFeedRate.addLine( self.getLinearMoveWithFeedRate( feedRate, locationBack ) )
166                 self.startupStepIndex += 1
167
168         def addLineSetShutdowns(self, line):
169                 "Add a line and set the shutdown variables."
170                 self.distanceFeedRate.addLine(line)
171                 self.isShutdownEarly = True
172
173         def getActiveFeedRateRatio(self):
174                 "Get the feed rate of the first active move over the operating feed rate."
175                 isSearchExtruderActive = self.isExtruderActive
176                 for afterIndex in xrange(self.lineIndex, len(self.lines)):
177                         line = self.lines[ afterIndex ]
178                         splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
179                         firstWord = gcodec.getFirstWord(splitLine)
180                         if firstWord == 'G1':
181                                 if isSearchExtruderActive:
182                                         return gcodec.getFeedRateMinute( self.feedRateMinute, splitLine ) / self.operatingFeedRateMinute
183                         elif firstWord == 'M101':
184                                 isSearchExtruderActive = True
185                 print('active feed rate ratio was not found in oozebane.')
186                 return 1.0
187
188         def getAddAfterStartupLines(self, line):
189                 "Get and / or add after the startup lines."
190                 splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
191                 while self.isDistanceAfterThreadBeginningGreater():
192                         self.addAfterStartupLine(splitLine)
193                 if self.startupStepIndex >= len( self.afterStartupDistances ):
194                         self.startupStepIndex = len( self.afterStartupDistances ) + 999999999999
195                         return self.getLinearMoveWithFeedRateSplitLine( self.operatingFeedRateMinute, splitLine )
196                 feedRate = self.operatingFeedRateMinute * self.getStartupFlowRateMultiplier( self.getDistanceAfterThreadBeginning() / self.afterStartupDistance, len( self.afterStartupDistances ) )
197                 return self.getLinearMoveWithFeedRateSplitLine( feedRate, splitLine )
198
199         def getAddBeforeStartupLines(self, line):
200                 "Get and / or add before the startup lines."
201                 distanceThreadBeginning = self.getDistanceToThreadBeginning()
202                 if distanceThreadBeginning == None:
203                         return line
204                 splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
205                 self.extruderInactiveLongEnough = False
206                 self.isStartupEarly = True
207                 location = gcodec.getLocationFromSplitLine(self.oldLocation, splitLine)
208                 segment = self.oldLocation - location
209                 segmentLength = segment.magnitude()
210                 distanceBack = self.earlyStartupDistance - distanceThreadBeginning
211                 if segmentLength <= 0.0:
212                         print('This should never happen, segmentLength is zero in getAddBeforeStartupLines in oozebane.')
213                         print(line)
214                         self.extruderInactiveLongEnough = True
215                         self.isStartupEarly = False
216                         return line
217                 locationBack = location + segment * distanceBack / segmentLength
218                 self.distanceFeedRate.addLine( self.getLinearMoveWithFeedRate( gcodec.getFeedRateMinute( self.feedRateMinute, splitLine ) , locationBack ) )
219                 self.distanceFeedRate.addLine('M101')
220                 if self.isCloseToEither( locationBack, location, self.oldLocation ):
221                         return ''
222                 return self.getLinearMoveWithFeedRate( self.operatingFeedRateMinute, location )
223
224         def getAddShutSlowDownLine(self, line):
225                 "Add the shutdown and slowdown lines."
226                 if self.shutdownStepIndex >= len( self.earlyShutdownDistances ):
227                         self.shutdownStepIndex = len( self.earlyShutdownDistances ) + 99999999
228                         return False
229                 splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
230                 distanceThreadEnd = self.getDistanceToExtruderOffCommand( self.earlyShutdownDistances[ self.shutdownStepIndex ] )
231                 location = gcodec.getLocationFromSplitLine(self.oldLocation, splitLine)
232                 if distanceThreadEnd == None:
233                         distanceThreadEnd = self.getDistanceToExtruderOffCommand( self.earlyShutdownDistances[0] )
234                         if distanceThreadEnd != None:
235                                 shutdownFlowRateMultiplier = self.getShutdownFlowRateMultiplier( 1.0 - distanceThreadEnd / self.earlyShutdownDistance, len( self.earlyShutdownDistances ) )
236                                 line = self.getLinearMoveWithFeedRate( self.feedRateMinute * shutdownFlowRateMultiplier, location )
237                         self.distanceFeedRate.addLine(line)
238                         return False
239                 segment = self.oldLocation - location
240                 segmentLength = segment.magnitude()
241                 distanceBack = self.earlyShutdownDistances[ self.shutdownStepIndex ] - distanceThreadEnd
242                 locationBack = location
243                 if segmentLength > 0.0:
244                         locationBack = location + segment * distanceBack / segmentLength
245                 if self.shutdownStepIndex == 0:
246                         if not self.isCloseToEither( locationBack, location, self.oldLocation ):
247                                 line = self.getLinearMoveWithFeedRate( self.feedRateMinute, locationBack )
248                         self.distanceFeedRate.addLine(line)
249                         self.addLineSetShutdowns('M103')
250                         return True
251                 if self.isClose( locationBack, self.oldLocation ):
252                         return True
253                 feedRate = self.feedRateMinute * self.earlyShutdownFlowRates[ self.shutdownStepIndex ]
254                 line = self.getLinearMoveWithFeedRate( feedRate, locationBack )
255                 if self.isClose( locationBack, location ):
256                         line = self.getLinearMoveWithFeedRate( feedRate, location )
257                 self.distanceFeedRate.addLine(line)
258                 return True
259
260         def getAddShutSlowDownLines(self, line):
261                 "Get and / or add the shutdown and slowdown lines."
262                 while self.getAddShutSlowDownLine(line):
263                         self.shutdownStepIndex += 1
264                 return ''
265
266         def getCraftedGcode( self, gcodeText, oozebaneRepository ):
267                 "Parse gcode text and store the oozebane gcode."
268                 self.lines = archive.getTextLines(gcodeText)
269                 self.oozebaneRepository = oozebaneRepository
270                 self.parseInitialization( oozebaneRepository )
271                 for self.lineIndex in xrange(self.lineIndex, len(self.lines)):
272                         line = self.lines[self.lineIndex]
273                         self.parseLine(line)
274                 return self.distanceFeedRate.output.getvalue()
275
276         def getDistanceAfterThreadBeginning(self):
277                 "Get the distance after the beginning of the thread."
278                 line = self.lines[self.lineIndex]
279                 splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
280                 lastThreadLocation = gcodec.getLocationFromSplitLine(self.oldLocation, splitLine)
281                 totalDistance = 0.0
282                 extruderOnReached = False
283                 for beforeIndex in xrange( self.lineIndex - 1, 3, - 1 ):
284                         line = self.lines[ beforeIndex ]
285                         splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
286                         firstWord = gcodec.getFirstWord(splitLine)
287                         if firstWord == 'G1':
288                                 location = gcodec.getLocationFromSplitLine( lastThreadLocation, splitLine )
289                                 totalDistance += location.distance( lastThreadLocation )
290                                 lastThreadLocation = location
291                                 if extruderOnReached:
292                                         return totalDistance
293                         elif firstWord == 'M101':
294                                 extruderOnReached = True
295                 return None
296
297         def getDistanceToExtruderOffCommand( self, remainingDistance ):
298                 "Get the distance to the word."
299                 line = self.lines[self.lineIndex]
300                 splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
301                 lastThreadLocation = gcodec.getLocationFromSplitLine(self.oldLocation, splitLine)
302                 totalDistance = 0.0
303                 for afterIndex in xrange( self.lineIndex + 1, len(self.lines) ):
304                         line = self.lines[ afterIndex ]
305                         splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
306                         firstWord = gcodec.getFirstWord(splitLine)
307                         if firstWord == 'G1':
308                                 location = gcodec.getLocationFromSplitLine( lastThreadLocation, splitLine )
309                                 totalDistance += location.distance( lastThreadLocation )
310                                 lastThreadLocation = location
311                                 if totalDistance >= remainingDistance:
312                                         return None
313                         elif firstWord == 'M103':
314                                 return totalDistance
315                 return None
316
317         def getDistanceToThreadBeginning(self):
318                 "Get the distance to the beginning of the thread."
319                 if self.earlyStartupDistance == None:
320                         return None
321                 line = self.lines[self.lineIndex]
322                 splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
323                 lastThreadLocation = gcodec.getLocationFromSplitLine(self.oldLocation, splitLine)
324                 totalDistance = 0.0
325                 for afterIndex in xrange( self.lineIndex + 1, len(self.lines) ):
326                         line = self.lines[ afterIndex ]
327                         splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
328                         firstWord = gcodec.getFirstWord(splitLine)
329                         if firstWord == 'G1':
330                                 location = gcodec.getLocationFromSplitLine( lastThreadLocation, splitLine )
331                                 totalDistance += location.distance( lastThreadLocation )
332                                 lastThreadLocation = location
333                                 if totalDistance >= self.earlyStartupDistance:
334                                         return None
335                         elif firstWord == 'M101':
336                                 return totalDistance
337                 return None
338
339         def getDistanceToThreadBeginningAfterThreadEnd( self, remainingDistance ):
340                 "Get the distance to the thread beginning after the end of this thread."
341                 extruderOnReached = False
342                 line = self.lines[self.lineIndex]
343                 splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
344                 lastThreadLocation = gcodec.getLocationFromSplitLine(self.oldLocation, splitLine)
345                 threadEndReached = False
346                 totalDistance = 0.0
347                 for afterIndex in xrange( self.lineIndex + 1, len(self.lines) ):
348                         line = self.lines[ afterIndex ]
349                         splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
350                         firstWord = gcodec.getFirstWord(splitLine)
351                         if firstWord == 'G1':
352                                 location = gcodec.getLocationFromSplitLine( lastThreadLocation, splitLine )
353                                 if threadEndReached:
354                                         totalDistance += location.distance( lastThreadLocation )
355                                         if totalDistance >= remainingDistance:
356                                                 return None
357                                         if extruderOnReached:
358                                                 return totalDistance
359                                 lastThreadLocation = location
360                         elif firstWord == 'M101':
361                                 extruderOnReached = True
362                         elif firstWord == 'M103':
363                                 threadEndReached = True
364                 return None
365
366         def getDistanceToThreadEnd(self):
367                 "Get the distance to the end of the thread."
368                 if self.shutdownStepIndex >= len( self.earlyShutdownDistances ):
369                         return None
370                 return self.getDistanceToExtruderOffCommand( self.earlyShutdownDistances[ self.shutdownStepIndex ] )
371
372         def getLinearMoveWithFeedRate( self, feedRate, location ):
373                 "Get a linear move line with the feed rate."
374                 return self.distanceFeedRate.getLinearGcodeMovementWithFeedRate( feedRate, location.dropAxis(), location.z )
375
376         def getLinearMoveWithFeedRateSplitLine( self, feedRate, splitLine ):
377                 "Get a linear move line with the feed rate and split line."
378                 location = gcodec.getLocationFromSplitLine(self.oldLocation, splitLine)
379                 return self.getLinearMoveWithFeedRate( feedRate, location )
380
381         def getOozebaneLine(self, line):
382                 "Get oozebaned gcode line."
383                 splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
384                 self.feedRateMinute = gcodec.getFeedRateMinute( self.feedRateMinute, splitLine )
385                 if self.oldLocation == None:
386                         return line
387                 if self.startupStepIndex < len( self.afterStartupDistances ):
388                         return self.getAddAfterStartupLines(line)
389                 if self.extruderInactiveLongEnough:
390                         return self.getAddBeforeStartupLines(line)
391                 if self.shutdownStepIndex < len( self.earlyShutdownDistances ):
392                         return self.getAddShutSlowDownLines(line)
393                 if self.isStartupEarly:
394                         return self.getLinearMoveWithFeedRateSplitLine( self.operatingFeedRateMinute, splitLine )
395                 return line
396
397         def getShutdownFlowRateMultiplier( self, along, numberOfDistances ):
398                 "Get the shut down flow rate multipler."
399                 if numberOfDistances <= 0:
400                         return 1.0
401                 return 1.0 - 0.5 / float( numberOfDistances ) - along * float( numberOfDistances - 1 ) / float( numberOfDistances )
402
403         def getStartupFlowRateMultiplier( self, along, numberOfDistances ):
404                 "Get the startup flow rate multipler."
405                 if numberOfDistances <= 0:
406                         return 1.0
407                 return min( 1.0, 0.5 / float( numberOfDistances ) + along )
408
409         def isClose( self, location, otherLocation ):
410                 "Determine if the location is close to the other location."
411                 return location.distanceSquared( otherLocation ) < self.closeSquared
412
413         def isCloseToEither( self, location, otherLocationFirst, otherLocationSecond ):
414                 "Determine if the location is close to the other locations."
415                 if self.isClose( location, otherLocationFirst ):
416                         return True
417                 return self.isClose( location, otherLocationSecond )
418
419         def isDistanceAfterThreadBeginningGreater(self):
420                 "Determine if the distance after the thread beginning is greater than the step index after startup distance."
421                 if self.startupStepIndex >= len( self.afterStartupDistances ):
422                         return False
423                 return self.getDistanceAfterThreadBeginning() > self.afterStartupDistances[ self.startupStepIndex ]
424
425         def parseInitialization( self, oozebaneRepository ):
426                 'Parse gcode initialization and store the parameters.'
427                 for self.lineIndex in xrange(len(self.lines)):
428                         line = self.lines[self.lineIndex]
429                         splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
430                         firstWord = gcodec.getFirstWord(splitLine)
431                         self.distanceFeedRate.parseSplitLine(firstWord, splitLine)
432                         if firstWord == '(</extruderInitialization>)':
433                                 self.distanceFeedRate.addTagBracketedProcedure('oozebane')
434                                 return
435                         elif firstWord == '(<operatingFeedRatePerSecond>':
436                                 self.operatingFeedRateMinute = 60.0 * float(splitLine[1])
437                                 self.feedRateMinute = self.operatingFeedRateMinute
438                         elif firstWord == '(<edgeWidth>':
439                                 self.edgeWidth = float(splitLine[1])
440                                 self.setExtrusionWidth( oozebaneRepository )
441                         self.distanceFeedRate.addLine(line)
442
443         def parseLine(self, line):
444                 "Parse a gcode line and add it to the bevel gcode."
445                 splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
446                 if len(splitLine) < 1:
447                         return
448                 firstWord = splitLine[0]
449                 if firstWord == 'G1':
450                         self.setEarlyStartupDistance(splitLine)
451                         line = self.getOozebaneLine(line)
452                         self.oldLocation = gcodec.getLocationFromSplitLine(self.oldLocation, splitLine)
453                 elif firstWord == 'M101':
454                         self.isExtruderActive = True
455                         self.extruderInactiveLongEnough = False
456                         if self.getDistanceToExtruderOffCommand( self.earlyShutdownDistance ) == None:
457                                 self.setEarlyShutdown()
458                         if self.getDistanceToExtruderOffCommand( 1.03 * ( self.earlyShutdownDistance + self.afterStartupDistance ) ) == None:
459                                 afterStartupRatio = 1.0
460                                 if self.minimumDistanceForEarlyStartup > 0.0:
461                                         if self.distanceFromThreadEndToThreadBeginning != None:
462                                                 afterStartupRatio = self.distanceFromThreadEndToThreadBeginning / self.minimumDistanceForEarlyStartup
463                                 self.setAfterStartupFlowRates( afterStartupRatio )
464                                 self.startupStepIndex = 9999999999
465                                 if len( self.afterStartupDistances ) > 0:
466                                         self.startupStepIndex = 0
467                         if self.isStartupEarly:
468                                 self.isStartupEarly = False
469                                 return
470                 elif firstWord == 'M103':
471                         self.isExtruderActive = False
472                         self.shutdownStepIndex = 999999999
473                         if self.getDistanceToThreadBeginning() == None:
474                                 self.extruderInactiveLongEnough = True
475                         self.distanceFromThreadEndToThreadBeginning = None
476                         self.earlyStartupDistance = None
477                         if self.isShutdownEarly:
478                                 self.isShutdownEarly = False
479                                 return
480                 self.distanceFeedRate.addLine(line)
481
482         def setAfterStartupFlowRates( self, afterStartupRatio ):
483                 "Set the after startup flow rates."
484                 afterStartupRatio = min( 1.0, afterStartupRatio )
485                 afterStartupRatio = max( 0.0, afterStartupRatio )
486                 self.afterStartupDistance = afterStartupRatio * self.getActiveFeedRateRatio() * self.oozebaneRepository.afterStartupDistance.value
487                 self.afterStartupDistances = []
488                 self.afterStartupFlowRate = 1.0
489                 self.afterStartupFlowRates = []
490                 afterStartupSteps = int( math.floor( afterStartupRatio * float( self.oozebaneRepository.slowdownStartupSteps.value ) ) )
491                 if afterStartupSteps < 1:
492                         return
493                 if afterStartupSteps < 2:
494                         afterStartupSteps = 2
495                 for stepIndex in xrange( afterStartupSteps ):
496                         afterWay = ( stepIndex + 1 ) / float( afterStartupSteps )
497                         afterMiddleWay = self.getStartupFlowRateMultiplier( stepIndex / float( afterStartupSteps ), afterStartupSteps )
498                         self.afterStartupDistances.append( afterWay * self.afterStartupDistance )
499                         if stepIndex == 0:
500                                 self.afterStartupFlowRate = afterMiddleWay
501                         else:
502                                 self.afterStartupFlowRates.append( afterMiddleWay )
503                 if afterStartupSteps > 0:
504                         self.afterStartupFlowRates.append(1.0)
505
506         def setEarlyShutdown(self):
507                 "Set the early shutdown variables."
508                 distanceToThreadBeginning = self.getDistanceToThreadBeginningAfterThreadEnd( self.minimumDistanceForEarlyShutdown )
509                 earlyShutdownRatio = 1.0
510                 if distanceToThreadBeginning != None:
511                         if self.minimumDistanceForEarlyShutdown > 0.0:
512                                 earlyShutdownRatio = distanceToThreadBeginning / self.minimumDistanceForEarlyShutdown
513                 self.setEarlyShutdownFlowRates( earlyShutdownRatio )
514                 if len( self.earlyShutdownDistances ) > 0:
515                         self.shutdownStepIndex = 0
516
517         def setEarlyShutdownFlowRates( self, earlyShutdownRatio ):
518                 "Set the extrusion width."
519                 earlyShutdownRatio = min( 1.0, earlyShutdownRatio )
520                 earlyShutdownRatio = max( 0.0, earlyShutdownRatio )
521                 self.earlyShutdownDistance = earlyShutdownRatio * self.getActiveFeedRateRatio() * self.oozebaneRepository.earlyShutdownDistance.value
522                 self.earlyShutdownDistances = []
523                 self.earlyShutdownFlowRates = []
524                 earlyShutdownSteps = int( math.floor( earlyShutdownRatio * float( self.oozebaneRepository.slowdownStartupSteps.value ) ) )
525                 if earlyShutdownSteps < 2:
526                         earlyShutdownSteps = 0
527                 earlyShutdownStepsMinusOne = float( earlyShutdownSteps ) - 1.0
528                 for stepIndex in xrange( earlyShutdownSteps ):
529                         downMiddleWay = self.getShutdownFlowRateMultiplier( stepIndex / earlyShutdownStepsMinusOne, earlyShutdownSteps )
530                         downWay = 1.0 - stepIndex / earlyShutdownStepsMinusOne
531                         self.earlyShutdownFlowRates.append( downMiddleWay )
532                         self.earlyShutdownDistances.append( downWay * self.earlyShutdownDistance )
533
534         def setEarlyStartupDistance( self, splitLine ):
535                 "Set the early startup distance."
536                 if self.earlyStartupDistance != None:
537                         return
538                 self.distanceFromThreadEndToThreadBeginning = 0.0
539                 lastThreadLocation = gcodec.getLocationFromSplitLine(self.oldLocation, splitLine)
540                 if self.oldLocation != None:
541                         self.distanceFromThreadEndToThreadBeginning = lastThreadLocation.distance( self.oldLocation )
542                 for afterIndex in xrange( self.lineIndex + 1, len(self.lines) ):
543                         line = self.lines[ afterIndex ]
544                         splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
545                         firstWord = gcodec.getFirstWord(splitLine)
546                         if firstWord == 'G1':
547                                 location = gcodec.getLocationFromSplitLine( lastThreadLocation, splitLine )
548                                 self.distanceFromThreadEndToThreadBeginning += location.distance( lastThreadLocation )
549                                 lastThreadLocation = location
550                         elif firstWord == 'M101':
551                                 distanceConstantRatio = self.distanceFromThreadEndToThreadBeginning / self.earlyStartupDistanceConstant
552                                 earlyStartupOperatingDistance = self.earlyStartupMaximumDistance * ( 1.0 - math.exp( - distanceConstantRatio ) )
553                                 if self.isFirstExtrusion:
554                                         earlyStartupOperatingDistance = self.oozebaneRepository.firstEarlyStartupDistance.value
555                                         self.isFirstExtrusion = False
556                                 self.earlyStartupDistance = earlyStartupOperatingDistance * self.getActiveFeedRateRatio()
557                                 return
558
559         def setExtrusionWidth( self, oozebaneRepository ):
560                 "Set the extrusion width."
561                 self.closeSquared = 0.01 * self.edgeWidth * self.edgeWidth
562                 self.earlyStartupMaximumDistance = oozebaneRepository.earlyStartupMaximumDistance.value
563                 self.earlyStartupDistanceConstant = oozebaneRepository.earlyStartupDistanceConstant.value
564                 self.minimumDistanceForEarlyStartup = oozebaneRepository.minimumDistanceForEarlyStartup.value
565                 self.minimumDistanceForEarlyShutdown = oozebaneRepository.minimumDistanceForEarlyShutdown.value
566                 self.setEarlyShutdownFlowRates(1.0)
567                 self.setAfterStartupFlowRates(1.0)
568
569
570 def main():
571         "Display the oozebane dialog."
572         if len(sys.argv) > 1:
573                 writeOutput(' '.join(sys.argv[1 :]))
574         else:
575                 settings.startMainLoopFromConstructor(getNewRepository())
576
577 if __name__ == "__main__":
578         main()