2 This page is in the table of contents.
3 Carve is the most important plugin to define for your printer.
5 It carves a shape into svg slice layers. It also sets the layer height and edge width for the rest of the tool chain.
7 The carve manual page is at:
8 http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Carve
10 On the Arcol Blog a method of deriving the layer height is posted. That article "Machine Calibrating" is at:
11 http://blog.arcol.hu/?p=157
14 ===Add Layer Template to SVG===
17 When selected, the layer template will be added to the svg output, which adds javascript control boxes. So 'Add Layer Template to SVG' should be selected when the svg will be viewed in a browser.
19 When off, no controls will be added, the svg output will only include the fabrication paths. So 'Add Layer Template to SVG' should be deselected when the svg will be used by other software, like Inkscape.
21 ===Edge Width over Height===
24 Defines the ratio of the extrusion edge width to the layer height. This parameter tells skeinforge how wide the edge wall is expected to be in relation to the layer height. Default value of 1.8 for the default layer height of 0.4 states that a single filament edge wall should be 0.4 mm * 1.8 = 0.72 mm wide. The higher the value the more the edge will be inset. A ratio of one means the extrusion is a circle, the default ratio of 1.8 means the extrusion is a wide oval.
26 This is an important value because if you are calibrating your machine you need to ensure that the speed of the head and the extrusion rate in combination produce a wall that is 'Layer Height' * 'Edge Width over Height' wide. To start with 'Edge Width over Height' is probably best left at the default of 1.8 and the extrusion rate adjusted to give the correct calculated wall thickness.
28 Adjustment is in the 'Speed' section with 'Feed Rate' controlling speed of the head in X & Y and 'Flow Rate' controlling the extrusion rate. Initially it is probably easier to start adjusting the flow rate only a little at a time until you get a single filament of the correct width. If you change too many parameters at once you can get in a right mess.
30 ===Extra Decimal Places===
33 Defines the number of extra decimal places export will output compared to the number of decimal places in the layer height. The higher the 'Extra Decimal Places', the more significant figures the output numbers will have.
35 ===Import Coarseness===
38 When a triangle mesh has holes in it, the triangle mesh slicer switches over to a slow algorithm that spans gaps in the mesh. The higher the 'Import Coarseness' setting, the wider the gaps in the mesh it will span. An import coarseness of one means it will span gaps of the edge width.
43 Defines the the height of the layers skeinforge will cut your object into, in the z direction. This is the most important carve setting, many values in the toolchain are derived from the layer height.
45 For a 0.5 mm nozzle usable values are 0.3 mm to 0.5 mm. Note; if you are using thinner layers make sure to adjust the extrusion speed as well.
48 Carve slices from bottom to top. To get a single layer, set the "Layers From" to zero and the "Layers To" to one. The 'Layers From' until 'Layers To' range is a python slice.
53 Defines the index of the bottom layer that will be carved. If the 'Layers From' is the default zero, the carving will start from the lowest layer. If the 'Layers From' index is negative, then the carving will start from the 'Layers From' index below the top layer.
55 For example if your object is 5 mm tall and your layer thicknes is 1 mm if you set layers from to 3 you will ignore the first 3 mm and start from 3 mm.
58 Default is a huge number, which will be limited to the highest index layer.
60 Defines the index of the top layer that will be carved. If the 'Layers To' index is a huge number like the default, the carving will go to the top of the model. If the 'Layers To' index is negative, then the carving will go to the 'Layers To' index below the top layer.
62 This is the same as layers from, only it defines when to end the generation of gcode.
65 Default is 'Correct Mesh'.
68 When selected, the mesh will be accurately carved, and if a hole is found, carve will switch over to the algorithm that spans gaps.
71 When selected, carve will use the gap spanning algorithm from the start. The problem with the gap spanning algothm is that it will span gaps, even if there is not actually a gap in the model.
74 Default is webbrowser.
76 If the 'SVG Viewer' is set to the default 'webbrowser', the scalable vector graphics file will be sent to the default browser to be opened. If the 'SVG Viewer' is set to a program name, the scalable vector graphics file will be sent to that program to be opened.
79 The following examples carve the file Screw Holder Bottom.stl. The examples are run in a terminal in the folder which contains Screw Holder Bottom.stl and carve.py.
82 This brings up the carve dialog.
84 > python carve.py Screw Holder Bottom.stl
85 The carve tool is parsing the file:
86 Screw Holder Bottom.stl
88 The carve tool has created the file:
89 .. Screw Holder Bottom_carve.svg
93 from __future__ import absolute_import
99 #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.
102 from fabmetheus_utilities.fabmetheus_tools import fabmetheus_interpret
103 from fabmetheus_utilities import archive
104 from fabmetheus_utilities import euclidean
105 from fabmetheus_utilities import gcodec
106 from fabmetheus_utilities import settings
107 from fabmetheus_utilities import svg_writer
108 from skeinforge_application.skeinforge_utilities import skeinforge_polyfile
109 from skeinforge_application.skeinforge_utilities import skeinforge_profile
110 from fabmetheus_utilities.vector3 import Vector3
118 __author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
119 __date__ = '$Date: 2008/02/05 $'
120 __license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
123 def getCraftedText( fileName, gcodeText = '', repository=None):
125 if fileName.endswith('.svg'):
126 gcodeText = archive.getTextIfEmpty(fileName, gcodeText)
127 if gcodec.isProcedureDoneOrFileIsEmpty( gcodeText, 'carve'):
129 carving = svg_writer.getCarving(fileName)
132 if repository == None:
133 repository = CarveRepository()
134 settings.getReadRepository(repository)
135 return CarveSkein().getCarvedSVG( carving, fileName, repository )
137 def getNewRepository():
138 'Get new repository.'
139 return CarveRepository()
141 def writeOutput(fileName, shouldAnalyze=True):
142 "Carve a GNU Triangulated Surface file."
143 startTime = time.time()
144 print('File ' + archive.getSummarizedFileName(fileName) + ' is being carved.')
145 repository = CarveRepository()
146 settings.getReadRepository(repository)
147 carveGcode = getCraftedText(fileName, '', repository)
150 suffixFileName = archive.getFilePathWithUnderscoredBasename(fileName, '_carve.svg')
151 archive.writeFileText(suffixFileName, carveGcode)
152 print('The carved file is saved as ' + archive.getSummarizedFileName(suffixFileName))
153 print('It took %s to carve the file.' % euclidean.getDurationString(time.time() - startTime))
155 settings.openSVGPage(suffixFileName, repository.svgViewer.value)
158 class CarveRepository:
159 "A class to handle the carve settings."
161 "Set the default settings, execute title & settings fileName."
162 skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.carve.html', self )
163 self.fileNameInput = settings.FileNameInput().getFromFileName( fabmetheus_interpret.getTranslatorFileTypeTuples(), 'Open File for Carve', self, '')
164 self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Carve')
165 self.addLayerTemplateToSVG = settings.BooleanSetting().getFromValue('Add Layer Template to SVG', self, True)
166 self.edgeWidth = settings.FloatSpin().getFromValue( 0.1, 'Edge Width (mm):', self, 2.2, 0.4 )
167 self.extraDecimalPlaces = settings.FloatSpin().getFromValue(0.0, 'Extra Decimal Places (float):', self, 3.0, 2.0)
168 self.importCoarseness = settings.FloatSpin().getFromValue( 0.5, 'Import Coarseness (ratio):', self, 2.0, 1.0 )
169 self.layerHeight = settings.FloatSpin().getFromValue( 0.1, 'Layer Height (mm):', self, 1.0, 0.2 )
170 settings.LabelSeparator().getFromRepository(self)
171 settings.LabelDisplay().getFromName('- Layers -', self )
172 self.layersFrom = settings.IntSpin().getFromValue( 0, 'Layers From (index):', self, 20, 0 )
173 self.layersTo = settings.IntSpin().getSingleIncrementFromValue( 0, 'Layers To (index):', self, 912345678, 912345678 )
174 settings.LabelSeparator().getFromRepository(self)
175 self.meshTypeLabel = settings.LabelDisplay().getFromName('Mesh Type: ', self )
176 importLatentStringVar = settings.LatentStringVar()
177 self.correctMesh = settings.Radio().getFromRadio( importLatentStringVar, 'Correct Mesh', self, True )
178 self.unprovenMesh = settings.Radio().getFromRadio( importLatentStringVar, 'Unproven Mesh', self, False )
179 self.svgViewer = settings.StringSetting().getFromValue('SVG Viewer:', self, 'webbrowser')
180 settings.LabelSeparator().getFromRepository(self)
181 self.executeTitle = 'Carve'
183 self.flipX = settings.BooleanSetting().getFromValue('FlipX', self, False)
184 self.flipY = settings.BooleanSetting().getFromValue('FlipY', self, False)
185 self.flipZ = settings.BooleanSetting().getFromValue('FlipZ', self, False)
186 self.scale = settings.FloatSpin().getFromValue( 0.1, 'Scale', self, 10.0, 1.0 )
187 self.rotate = settings.FloatSpin().getFromValue( -180.0, 'Rotate', self, 180.0, 0.0 )
191 "Carve button has been clicked."
192 fileNames = skeinforge_polyfile.getFileOrDirectoryTypes(self.fileNameInput.value, fabmetheus_interpret.getImportPluginFileNames(), self.fileNameInput.wasCancelled)
193 for fileName in fileNames:
194 writeOutput(fileName)
198 "A class to carve a carving."
199 def getCarvedSVG(self, carving, fileName, repository):
200 "Parse gnu triangulated surface text and store the carved gcode."
202 scale = repository.scale.value
203 rotate = repository.rotate.value / 180 * math.pi
207 if repository.flipX.value == True:
209 if repository.flipY.value == True:
211 if repository.flipZ.value == True:
213 mat00 = math.cos(rotate) * scaleX
214 mat01 =-math.sin(rotate) * scaleY
215 mat10 = math.sin(rotate) * scaleX
216 mat11 = math.cos(rotate) * scaleY
218 minZ = carving.getMinimumZ()
219 minSize = carving.getCarveCornerMinimum()
220 maxSize = carving.getCarveCornerMaximum()
221 for v in carving.vertexes:
223 v.x -= minSize.x + (maxSize.x - minSize.x) / 2
224 v.y -= minSize.y + (maxSize.y - minSize.y) / 2
225 #v.x += self.machineCenter.x
226 #v.y += self.machineCenter.y
228 for i in xrange(0, len(carving.vertexes)):
229 carving.vertexes[i] = Vector3(
230 carving.vertexes[i].x * mat00 + carving.vertexes[i].y * mat01,
231 carving.vertexes[i].x * mat10 + carving.vertexes[i].y * mat11,
232 carving.vertexes[i].z * scaleZ)
234 layerHeight = repository.layerHeight.value
235 edgeWidth = repository.edgeWidth.value
236 carving.setCarveLayerHeight(layerHeight)
237 importRadius = 0.5 * repository.importCoarseness.value * abs(edgeWidth)
238 carving.setCarveImportRadius(max(importRadius, 0.001 * layerHeight))
239 carving.setCarveIsCorrectMesh(repository.correctMesh.value)
240 loopLayers = carving.getCarveBoundaryLayers()
241 if len(loopLayers) < 1:
242 print('Warning, there are no slices for the model, this could be because the model is too small for the Layer Height.')
244 layerHeight = carving.getCarveLayerHeight()
245 decimalPlacesCarried = euclidean.getDecimalPlacesCarried(repository.extraDecimalPlaces.value, layerHeight)
246 edgeWidth = repository.edgeWidth.value
247 svgWriter = svg_writer.SVGWriter(
248 repository.addLayerTemplateToSVG.value,
249 carving.getCarveCornerMaximum(),
250 carving.getCarveCornerMinimum(),
251 decimalPlacesCarried,
252 carving.getCarveLayerHeight(),
254 truncatedRotatedBoundaryLayers = svg_writer.getTruncatedRotatedBoundaryLayers(loopLayers, repository)
255 return svgWriter.getReplacedSVGTemplate(fileName, truncatedRotatedBoundaryLayers, 'carve', carving.getFabmetheusXML())
259 "Display the carve dialog."
260 if len(sys.argv) > 1:
261 writeOutput(' '.join(sys.argv[1 :]))
263 settings.startMainLoopFromConstructor(getNewRepository())
265 if __name__ == "__main__":