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
21 #Init has to be imported first because it has code to workaround the python bug where relative imports don't work if the module is imported as a main module.
24 from fabmetheus_utilities.fabmetheus_tools import fabmetheus_interpret
25 from fabmetheus_utilities.geometry.solids import triangle_mesh
26 from fabmetheus_utilities.vector3 import Vector3
27 from fabmetheus_utilities import archive
28 from fabmetheus_utilities import euclidean
29 from fabmetheus_utilities import gcodec
30 from fabmetheus_utilities import intercircle
31 from fabmetheus_utilities import settings
32 from skeinforge_application.skeinforge_utilities import skeinforge_craft
33 from skeinforge_application.skeinforge_utilities import skeinforge_polyfile
34 from skeinforge_application.skeinforge_utilities import skeinforge_profile
38 __author__ = 'Daid (daid303@gmail.com'
39 __date__ = '$Date: 2012/24/01 $'
40 __license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
43 def getCraftedText(fileName, gcodeText, repository=None):
44 'Joris a gcode linear move text.'
45 return getCraftedTextFromText(archive.getTextIfEmpty(fileName, gcodeText), repository)
47 def getCraftedTextFromText(gcodeText, repository=None):
48 'Joris a gcode linear move text.'
49 if gcodec.isProcedureDoneOrFileIsEmpty(gcodeText, 'Joris'):
51 if repository == None:
52 repository = settings.getReadRepository(JorisRepository())
53 if not repository.activateJoris.value:
55 return JorisSkein().getCraftedGcode(gcodeText, repository)
57 def getIsMinimumSides(loops, sides=3):
58 'Determine if all the loops have at least the given number of sides.'
64 def getNewRepository():
66 return JorisRepository()
68 def writeOutput(fileName, shouldAnalyze=True):
69 'Joris a gcode linear move file. Chain Joris the gcode if it is not already Jorised.'
70 skeinforge_craft.writeChainTextWithNounMessage(fileName, 'joris', shouldAnalyze)
73 class JorisRepository:
74 'A class to handle the Joris settings.'
76 'Set the default settings, execute title & settings fileName.'
77 skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.joris.html', self )
78 self.fileNameInput = settings.FileNameInput().getFromFileName( fabmetheus_interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File for Joris', self, '')
79 self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Joris')
80 self.activateJoris = settings.BooleanSetting().getFromValue('Activate Joris', self, False)
81 settings.LabelSeparator().getFromRepository(self)
82 self.layersFrom = settings.IntSpin().getSingleIncrementFromValue(0, 'Layers From (index):', self, 912345678, 1)
83 self.executeTitle = 'Joris'
86 'Joris button has been clicked.'
87 fileNames = skeinforge_polyfile.getFileOrDirectoryTypesUnmodifiedGcode(self.fileNameInput.value, fabmetheus_interpret.getImportPluginFileNames(), self.fileNameInput.wasCancelled)
88 for fileName in fileNames:
93 'A class to Joris a skein of extrusions.'
96 self.distanceFeedRate = gcodec.DistanceFeedRate()
99 self.feedRateMinute = 959.0
100 self.travelFeedRateMinute = 957.0
101 self.perimeter = None
102 self.oldLocation = None
105 def getCraftedGcode( self, gcodeText, repository ):
106 'Parse gcode text and store the joris gcode.'
107 self.lines = archive.getTextLines(gcodeText)
108 self.repository = repository
109 self.layersFromBottom = repository.layersFrom.value
110 self.parseInitialization()
111 for self.lineIndex in xrange(self.lineIndex, len(self.lines)):
112 line = self.lines[self.lineIndex]
114 return gcodec.getGcodeWithoutDuplication('M108', self.distanceFeedRate.output.getvalue())
116 def parseInitialization(self):
117 'Parse gcode initialization and store the parameters.'
118 for self.lineIndex in xrange(len(self.lines)):
119 line = self.lines[self.lineIndex]
120 splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
121 firstWord = gcodec.getFirstWord(splitLine)
122 self.distanceFeedRate.parseSplitLine(firstWord, splitLine)
123 if firstWord == '(<layerThickness>':
124 self.layerThickness = float(splitLine[1])
125 elif firstWord == '(</extruderInitialization>)':
126 self.distanceFeedRate.addTagBracketedProcedure('joris')
128 elif firstWord == '(<travelFeedRatePerSecond>':
129 self.travelFeedRateMinute = 60.0 * float(splitLine[1])
130 self.distanceFeedRate.addLine(line)
132 def parseLine(self, line):
133 'Parse a gcode line and add it to the joris skein.'
134 splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
135 if len(splitLine) < 1:
137 firstWord = splitLine[0]
138 if firstWord == 'G1' and self.doJoris:
139 self.feedRateMinute = gcodec.getFeedRateMinute(self.feedRateMinute, splitLine)
140 location = gcodec.getLocationFromSplitLine(self.oldLocation, splitLine)
141 self.oldLocation = location
142 if self.perimeter != None:
143 self.perimeter.append(location.dropAxis())
145 elif firstWord == '(<layer>':
147 settings.printProgress(self.layerIndex, 'joris')
148 elif firstWord == 'M108':
149 self.oldFlowRate = gcodec.getDoubleAfterFirstLetter(splitLine[1])
150 elif firstWord == '(<edge>':
151 if self.layerIndex >= self.layersFromBottom:
153 elif firstWord == 'M101' and self.doJoris:
156 elif firstWord == 'M103' and self.doJoris:
157 self.addJorisedPerimeter()
159 elif firstWord == '(</edge>)':
161 self.distanceFeedRate.addLine(line)
163 def addJorisedPerimeter(self):
164 'Add jorised perimeter.'
165 if self.perimeter == None:
167 #Calculate the total length of the perimeter.
168 p = self.oldLocation.dropAxis()
170 for point in self.perimeter:
171 perimeterLength += abs( point - p );
174 #Build the perimeter with an increasing Z over the length.
175 p = self.oldLocation.dropAxis()
177 self.distanceFeedRate.addLine('M101') # Turn extruder on.
178 for point in self.perimeter:
179 len += abs( point - p );
181 self.distanceFeedRate.addGcodeMovementZWithFeedRate(self.feedRateMinute, point, self.oldLocation.z + self.layerThickness * len / perimeterLength)
182 self.distanceFeedRate.addLine('M103') # Turn extruder off.
183 self.perimeter = None