3 This page is in the table of contents.
4 Widen will widen the outside edges away from the inside edges, so that the outsides will be at least two edge widths away from the insides and therefore the outside filaments will not overlap the inside filaments.
6 For example, if a mug has a very thin wall, widen would widen the outside of the mug so that the wall of the mug would be two edge widths wide, and the outside wall filament would not overlap the inside filament.
8 For another example, if the outside of the object runs right next to a hole, widen would widen the wall around the hole so that the wall would bulge out around the hole, and the outside filament would not overlap the hole filament.
10 The widen manual page is at:
11 http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Widen
14 The default 'Activate Widen' checkbox is off. When it is on, widen will work, when it is off, nothing will be done.
17 The following examples widen the file Screw Holder Bottom.stl. The examples are run in a terminal in the folder which contains Screw Holder Bottom.stl and widen.py.
20 This brings up the widen dialog.
22 > python widen.py Screw Holder Bottom.stl
23 The widen tool is parsing the file:
24 Screw Holder Bottom.stl
26 The widen tool has created the file:
27 .. Screw Holder Bottom_widen.gcode
31 from __future__ import absolute_import
37 #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.
40 from fabmetheus_utilities.fabmetheus_tools import fabmetheus_interpret
41 from fabmetheus_utilities.geometry.geometry_utilities import boolean_solid
42 from fabmetheus_utilities.geometry.solids import triangle_mesh
43 from fabmetheus_utilities import archive
44 from fabmetheus_utilities import euclidean
45 from fabmetheus_utilities import gcodec
46 from fabmetheus_utilities import intercircle
47 from fabmetheus_utilities import settings
48 from skeinforge_application.skeinforge_utilities import skeinforge_craft
49 from skeinforge_application.skeinforge_utilities import skeinforge_polyfile
50 from skeinforge_application.skeinforge_utilities import skeinforge_profile
55 __author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
56 __date__ = '$Date: 2008/28/04 $'
57 __license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
60 def getCraftedText(fileName, text='', repository=None):
61 'Widen the preface file or text.'
62 return getCraftedTextFromText(archive.getTextIfEmpty(fileName, text), repository)
64 def getCraftedTextFromText(gcodeText, repository=None):
65 'Widen the preface gcode text.'
66 if gcodec.isProcedureDoneOrFileIsEmpty( gcodeText, 'widen'):
68 if repository == None:
69 repository = settings.getReadRepository( WidenRepository() )
70 if not repository.activateWiden.value:
72 return WidenSkein().getCraftedGcode(gcodeText, repository)
74 def getIntersectingWithinLoops(loop, loopList, outsetLoop):
75 'Get the loops which are intersecting or which it is within.'
76 intersectingWithinLoops = []
77 for otherLoop in loopList:
78 if getIsIntersectingWithinLoop(loop, otherLoop, outsetLoop):
79 intersectingWithinLoops.append(otherLoop)
80 return intersectingWithinLoops
82 def getIsIntersectingWithinLoop(loop, otherLoop, outsetLoop):
83 'Determine if the loop is intersecting or is within the other loop.'
84 if euclidean.isLoopIntersectingLoop(loop, otherLoop):
86 return euclidean.isPathInsideLoop(otherLoop, loop) != euclidean.isPathInsideLoop(otherLoop, outsetLoop)
88 def getIsPointInsideALoop(loops, point):
89 'Determine if a point is inside a loop of a loop list.'
91 if euclidean.isPointInsideLoop(loop, point):
95 def getNewRepository():
97 return WidenRepository()
99 def getWidenedLoops(loop, loopList, outsetLoop, radius):
100 'Get the widened loop.'
101 intersectingWithinLoops = getIntersectingWithinLoops(loop, loopList, outsetLoop)
102 if len(intersectingWithinLoops) < 1:
104 loopsUnified = boolean_solid.getLoopsUnion(radius, [[loop], intersectingWithinLoops])
105 if len(loopsUnified) < 1:
109 def writeOutput(fileName, shouldAnalyze=True):
110 'Widen the carving of a gcode file.'
111 skeinforge_craft.writeChainTextWithNounMessage(fileName, 'widen', shouldAnalyze)
114 class WidenRepository:
115 'A class to handle the widen settings.'
117 'Set the default settings, execute title & settings fileName.'
118 skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.widen.html', self)
119 self.fileNameInput = settings.FileNameInput().getFromFileName(
120 fabmetheus_interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File for Widen', self, '')
121 self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute(
122 'http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Widen')
123 self.activateWiden = settings.BooleanSetting().getFromValue('Activate Widen', self, False)
124 self.widenWidthOverEdgeWidth = settings.IntSpin().getFromValue(2, 'Widen Width over Edge Width (ratio):', self, 4, 2)
125 self.executeTitle = 'Widen'
128 'Widen button has been clicked.'
129 fileNames = skeinforge_polyfile.getFileOrDirectoryTypesUnmodifiedGcode(
130 self.fileNameInput.value, fabmetheus_interpret.getImportPluginFileNames(), self.fileNameInput.wasCancelled)
131 for fileName in fileNames:
132 writeOutput(fileName)
136 'A class to widen a skein of extrusions.'
139 self.distanceFeedRate = gcodec.DistanceFeedRate()
140 self.layerCount = settings.LayerCount()
142 self.loopLayer = None
144 def addWiden(self, loopLayer):
145 'Add widen to the layer.'
146 triangle_mesh.sortLoopsInOrderOfArea(False, loopLayer.loops)
147 widdershinsLoops = []
148 clockwiseInsetLoops = []
149 for loopIndex in xrange(len(loopLayer.loops)):
150 loop = loopLayer.loops[loopIndex]
151 if euclidean.isWiddershins(loop):
152 otherLoops = loopLayer.loops[: loopIndex] + loopLayer.loops[loopIndex + 1 :]
153 leftPoint = euclidean.getLeftPoint(loop)
154 if getIsPointInsideALoop(otherLoops, leftPoint):
155 self.distanceFeedRate.addGcodeFromLoop(loop, loopLayer.z)
157 widdershinsLoops.append(loop)
159 # clockwiseInsetLoop = intercircle.getLargestInsetLoopFromLoop(loop, self.widenEdgeWidth)
160 # clockwiseInsetLoop.reverse()
161 # clockwiseInsetLoops.append(clockwiseInsetLoop)
162 clockwiseInsetLoops += intercircle.getInsetLoopsFromLoop(loop, self.widenEdgeWidth)
163 self.distanceFeedRate.addGcodeFromLoop(loop, loopLayer.z)
164 for widdershinsLoop in widdershinsLoops:
165 outsetLoop = intercircle.getLargestInsetLoopFromLoop(widdershinsLoop, -self.widenEdgeWidth)
166 for widenedLoop in getWidenedLoops(widdershinsLoop, clockwiseInsetLoops, outsetLoop, self.lessThanHalfEdgeWidth):
167 self.distanceFeedRate.addGcodeFromLoop(widenedLoop, loopLayer.z)
169 def getCraftedGcode(self, gcodeText, repository):
170 'Parse gcode text and store the widen gcode.'
171 self.repository = repository
172 self.lines = archive.getTextLines(gcodeText)
173 self.parseInitialization()
174 for line in self.lines[self.lineIndex :]:
176 return self.distanceFeedRate.output.getvalue()
178 def parseInitialization(self):
179 'Parse gcode initialization and store the parameters.'
180 for self.lineIndex in xrange(len(self.lines)):
181 line = self.lines[self.lineIndex]
182 splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
183 firstWord = gcodec.getFirstWord(splitLine)
184 self.distanceFeedRate.parseSplitLine(firstWord, splitLine)
185 if firstWord == '(</extruderInitialization>)':
186 self.distanceFeedRate.addTagBracketedProcedure('widen')
187 elif firstWord == '(<crafting>)':
188 self.distanceFeedRate.addLine(line)
190 elif firstWord == '(<edgeWidth>':
191 self.edgeWidth = float(splitLine[1])
192 self.widenEdgeWidth = float(self.repository.widenWidthOverEdgeWidth.value) * self.edgeWidth
193 self.lessThanHalfEdgeWidth = 0.49 * self.edgeWidth
194 self.distanceFeedRate.addLine(line)
196 def parseLine(self, line):
197 'Parse a gcode line and add it to the widen skein.'
198 splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
199 if len(splitLine) < 1:
201 firstWord = splitLine[0]
202 if firstWord == '(<boundaryPoint>':
203 location = gcodec.getLocationFromSplitLine(None, splitLine)
204 self.boundary.append(location.dropAxis())
205 elif firstWord == '(<layer>':
206 self.layerCount.printProgressIncrement('widen')
207 self.loopLayer = euclidean.LoopLayer(float(splitLine[1]))
208 self.distanceFeedRate.addLine(line)
209 elif firstWord == '(</layer>)':
210 self.addWiden( self.loopLayer )
211 self.loopLayer = None
212 elif firstWord == '(<nestedRing>)':
214 self.loopLayer.loops.append( self.boundary )
215 if self.loopLayer == None:
216 self.distanceFeedRate.addLine(line)
220 'Display the widen dialog.'
221 if len(sys.argv) > 1:
222 writeOutput(' '.join(sys.argv[1 :]))
224 settings.startMainLoopFromConstructor(getNewRepository())
226 if __name__ == '__main__':