2 This page is in the table of contents.
3 The Joris plugin makes the perimiter slowly increase in Z over the layer. This will make vases/cups without a z blob.
6 The default 'Activate Joris' checkbox is off. When it is on, the Joris plugin will do it's work.
12 Defines which layer of the print the joris process starts from.
20 from __future__ import absolute_import
22 from fabmetheus_utilities.fabmetheus_tools import fabmetheus_interpret
23 from fabmetheus_utilities import archive
24 from fabmetheus_utilities import gcodec
25 from fabmetheus_utilities import settings
26 from skeinforge_application.skeinforge_utilities import skeinforge_craft
27 from skeinforge_application.skeinforge_utilities import skeinforge_polyfile
28 from skeinforge_application.skeinforge_utilities import skeinforge_profile
30 __author__ = 'Daid (daid303@gmail.com'
31 __date__ = '$Date: 2012/24/01 $'
32 __license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
35 def getCraftedText(fileName, gcodeText, repository=None):
36 'Joris a gcode linear move text.'
37 return getCraftedTextFromText(archive.getTextIfEmpty(fileName, gcodeText), repository)
39 def getCraftedTextFromText(gcodeText, repository=None):
40 'Joris a gcode linear move text.'
41 if gcodec.isProcedureDoneOrFileIsEmpty(gcodeText, 'Joris'):
43 if repository == None:
44 repository = settings.getReadRepository(JorisRepository())
45 if not repository.activateJoris.value:
47 return JorisSkein().getCraftedGcode(gcodeText, repository)
49 def getIsMinimumSides(loops, sides=3):
50 'Determine if all the loops have at least the given number of sides.'
56 def getNewRepository():
58 return JorisRepository()
60 def writeOutput(fileName, shouldAnalyze=True):
61 'Joris a gcode linear move file. Chain Joris the gcode if it is not already Jorised.'
62 skeinforge_craft.writeChainTextWithNounMessage(fileName, 'joris', shouldAnalyze)
65 class JorisRepository(object):
66 'A class to handle the Joris settings.'
68 'Set the default settings, execute title & settings fileName.'
69 skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.joris.html', self )
70 self.fileNameInput = settings.FileNameInput().getFromFileName( fabmetheus_interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File for Joris', self, '')
71 self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Joris')
72 self.activateJoris = settings.BooleanSetting().getFromValue('Activate Joris', self, False)
73 settings.LabelSeparator().getFromRepository(self)
74 self.layersFrom = settings.IntSpin().getSingleIncrementFromValue(0, 'Layers From (index):', self, 912345678, 1)
75 self.executeTitle = 'Joris'
78 'Joris button has been clicked.'
79 fileNames = skeinforge_polyfile.getFileOrDirectoryTypesUnmodifiedGcode(self.fileNameInput.value, fabmetheus_interpret.getImportPluginFileNames(), self.fileNameInput.wasCancelled)
80 for fileName in fileNames:
84 class JorisSkein(object):
85 'A class to Joris a skein of extrusions.'
88 self.distanceFeedRate = gcodec.DistanceFeedRate()
91 self.feedRateMinute = 959.0
92 self.travelFeedRateMinute = 957.0
94 self.oldLocation = None
96 self.firstLayer = True
98 def getCraftedGcode( self, gcodeText, repository ):
99 'Parse gcode text and store the joris gcode.'
100 self.lines = archive.getTextLines(gcodeText)
101 self.repository = repository
102 self.layersFromBottom = repository.layersFrom.value
103 self.parseInitialization()
104 for self.lineIndex in xrange(self.lineIndex, len(self.lines)):
105 line = self.lines[self.lineIndex]
107 return gcodec.getGcodeWithoutDuplication('M108', self.distanceFeedRate.output.getvalue())
109 def parseInitialization(self):
110 'Parse gcode initialization and store the parameters.'
111 for self.lineIndex in xrange(len(self.lines)):
112 line = self.lines[self.lineIndex]
113 splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
114 firstWord = gcodec.getFirstWord(splitLine)
115 self.distanceFeedRate.parseSplitLine(firstWord, splitLine)
116 if firstWord == '(<layerThickness>':
117 self.layerThickness = float(splitLine[1])
118 elif firstWord == '(</extruderInitialization>)':
119 self.distanceFeedRate.addTagBracketedProcedure('joris')
121 elif firstWord == '(<travelFeedRatePerSecond>':
122 self.travelFeedRateMinute = 60.0 * float(splitLine[1])
123 self.distanceFeedRate.addLine(line)
125 def parseLine(self, line):
126 'Parse a gcode line and add it to the joris skein.'
127 splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
128 if len(splitLine) < 1:
130 firstWord = splitLine[0]
131 if firstWord == 'G1' and self.doJoris:
132 self.feedRateMinute = gcodec.getFeedRateMinute(self.feedRateMinute, splitLine)
133 location = gcodec.getLocationFromSplitLine(self.oldLocation, splitLine)
134 self.oldLocation = location
135 if self.perimeter != None:
136 self.perimeter.append(location.dropAxis())
138 elif firstWord == '(<layer>':
140 settings.printProgress(self.layerIndex, 'joris')
141 elif firstWord == 'M108':
142 self.oldFlowRate = gcodec.getDoubleAfterFirstLetter(splitLine[1])
143 elif firstWord == '(<edge>':
144 if self.layerIndex >= self.layersFromBottom:
146 elif firstWord == 'M101' and self.doJoris:
149 elif firstWord == 'M103' and self.doJoris:
150 self.addJorisedPerimeter()
152 elif firstWord == '(</edge>)':
154 self.distanceFeedRate.addLine(line)
156 def addJorisedPerimeter(self):
157 'Add jorised perimeter.'
158 if self.perimeter is None:
160 #Calculate the total length of the perimeter.
161 p = self.oldLocation.dropAxis()
163 for point in self.perimeter:
164 perimeterLength += abs( point - p )
167 #Build the perimeter with an increasing Z over the length.
169 #On the first layer, we need to create an extra jorised perimeter, else we create a gap at the end of the perimeter.
170 p = self.oldLocation.dropAxis()
172 self.distanceFeedRate.addLine('M101') # Turn extruder on.
173 for point in self.perimeter:
174 length += abs( point - p );
176 self.distanceFeedRate.addGcodeMovementZWithFeedRate(self.feedRateMinute, point, self.oldLocation.z - self.layerThickness + self.layerThickness * length / perimeterLength)
177 self.distanceFeedRate.addLine('M103') # Turn extruder off.
178 self.firstLayer = False
180 p = self.oldLocation.dropAxis()
182 self.distanceFeedRate.addLine('M101') # Turn extruder on.
183 for point in self.perimeter:
184 length += abs( point - p );
186 self.distanceFeedRate.addGcodeMovementZWithFeedRate(self.feedRateMinute, point, self.oldLocation.z + self.layerThickness * length / perimeterLength)
187 self.distanceFeedRate.addLine('M103') # Turn extruder off.
188 self.perimeter = None