"""
Analyze is a script to analyze and comment a gcode file.
To run analyze, install python 2.x on your machine, which is avaliable from http://www.python.org/download/
Then in the folder which analyze is in, type 'python' in a shell to run the python interpreter. Finally type
'from analyze import *' to import this program.
To get documentation for this program, open a shell in the fill.py directory, then type 'pydoc fill.py'.
This example analyzes and comments the gcode file Hollow Square.gcode. This example is run in a terminal in the folder which contains Hollow Square.gcode and analyze.py.
>>> import fillet
Fillet has been imported.
The gcode files in this directory that are not already beveled or filleted are the following:
['Hollow Square.gcode']
>>> fillet.arcPoint()
File Hollow Square.gcode is being filleted into arc points.
( GCode generated by March 29,2007 Skeinforge )
( Extruder Initialization )
..
many lines of gcode
..
The arc point file is saved as Hollow Square_arc_point.gcode
>>> fillet.arcPointFile("Hollow Square.gcode")
File Hollow Square.gcode is being filleted into arc points.
..
The arc point file is saved as Hollow Square_arc_point.gcode
>>> fillet.arcPointFiles(["Hollow Square.gcode"])
File Hollow Square.gcode is being filleted into arc points.
..
The arc point file is saved as Hollow Square_arc_point.gcode
>>> fillet.arcRadius()
File Hollow Square.gcode is being filleted into arc radiuses.
..
The arc radius file is saved as Hollow Square_arc_radius.gcode
>>> fillet.arcRadiusFile("Hollow Square.gcode")
File Hollow Square.gcode is being filleted into arc radiuses.
..
The arc radius file is saved as Hollow Square_arc_radius.gcode
>>> fillet.arcRadiusFiles(["Hollow Square.gcode"])
File Hollow Square.gcode is being filleted into arc radiuses.
..
The arc radius file is saved as Hollow Square_arc_radius.gcode
>>> fillet.arcSegment()
File Hollow Square.gcode is being arc segmented.
..
The arc segment file is saved as Hollow Square_arc_segment.gcode
>>> fillet.arcSegmentFile("Hollow Square.gcode")
File Hollow Square.gcode is being arc segmented.
..
The arc segment file is saved as Hollow Square_arc_segment.gcode
>>> fillet.arcSegmentFiles(["Hollow Square.gcode"])
File Hollow Square.gcode is being arc segmented.
..
The arc segment file is saved as Hollow Square_arc_segment.gcode
"""
from vec3 import Vec3
import cStringIO
import euclidean
import gcodec
import math
import preferences
__author__ = "Enrique Perez (perez_enrique@yahoo.com)"
__credits__ = 'Nophead '
__date__ = "$Date: 2008/21/04 $"
__license__ = "GPL 3.0"
#add open webbrowser first time file is created choice
def getVectorGcode( gcodeText, vectorwritePreferences = None ):
"Write a gcode text."
if gcodeText == '':
return ''
if vectorwritePreferences == None:
vectorwritePreferences = VectorwritePreferences()
preferences.readPreferences( vectorwritePreferences )
skein = VectorwriteSkein()
skein.parseGcode( gcodeText, vectorwritePreferences )
return skein.vectorWindow.getVectorFormattedText()
def writeSkeinforgeVectorFile( filename ):
"Write scalable vector graphics for a skeinforge gcode file, if 'Write Scalable Vector Graphics for Skeinforge Chain' is selected."
vectorwritePreferences = VectorwritePreferences()
preferences.readPreferences( vectorwritePreferences )
if vectorwritePreferences.writeSkeinforgeSVG.value:
writeVectorFile( filename )
def writeVectorFile( filename = '' ):
"Write scalable vector graphics for a gcode file. If no filename is specified, write scalable vector graphics for the first gcode file in this folder."
if filename == '':
unmodified = gcodec.getFilesWithFileTypeWithoutWords( 'gcode' )
if len( unmodified ) == 0:
print( "There is no gcode file in this folder." )
return
filename = unmodified[ 0 ]
vectorwritePreferences = VectorwritePreferences()
preferences.readPreferences( vectorwritePreferences )
print( 'Scalable vector graphics are being generated for the file ' + gcodec.getSummarizedFilename( filename ) )
fileText = gcodec.getFileText( filename )
suffixFilename = filename[ : filename.rfind( '.' ) ] + '.svg'
suffixFilename = suffixFilename.replace( ' ', '_' )
gcodec.writeFileText( suffixFilename, getVectorGcode( fileText, vectorwritePreferences ) )
print( 'The scalable vector graphics file is saved as ' + gcodec.getSummarizedFilename( suffixFilename ) )
class VectorWindow:
"A class to accumulate a scalable vector graphics text."
def __init__( self ):
self.height = 0
self.leftMargin = 20
self.text = cStringIO.StringIO()
self.width = 0
def __repr__( self ):
"Get the string representation of this VectorWindow."
return str( self.height ) + ' ' + str( self.width )
def addColoredLine( self, pointFirst, pointSecond, colorName ):
"Add a colored line to the text."
cornerPlusHeight = self.height + self.bottomLeftCorner.imag
x1String = str( int( round( pointFirst.real - self.bottomLeftCorner.real + self.leftMargin ) ) )
x2String = str( int( round( pointSecond.real - self.bottomLeftCorner.real + self.leftMargin ) ) )
y1String = str( int( round( cornerPlusHeight - pointFirst.imag ) ) )
y2String = str( int( round( cornerPlusHeight - pointSecond.imag ) ) )
self.addLine( ' ' )
def addFontHeight( self, fontSize ):
"Add quadruple the font size to the height."
self.height += 4 * fontSize
def addLine( self, line ):
"Add a line to the text and a newline."
self.text.write( line + "\n" )
def addPane( self ):
"Add a new window pane for drawing lines."
self.height += self.topRightCorner.imag - self.bottomLeftCorner.imag
def addText( self, fontSize, line ):
"Add a colored line to the text."
yString = str( 3 * fontSize + self.height )
self.addLine( ' ' )
self.addLine( ' ' + line )
self.addLine( ' ' )
self.addFontHeight( fontSize )
self.width = max( self.width, fontSize * len( line ) )
def getVectorFormattedText( self ):
"Get the text in scalable vector graphics format."
textBeginning = '\n\n'
textBeginning += '\n'
def setPaneCorners( self, bottomLeftCorner, topRightCorner ):
"Set the corners for the window pane."
self.bottomLeftCorner = bottomLeftCorner
self.topRightCorner = topRightCorner
self.width = self.topRightCorner.real - self.bottomLeftCorner.real
class VectorwriteSkein:
"A class to write a get a scalable vector graphics text for a gcode skein."
def __init__( self ):
self.extrusionNumber = 0
self.extrusionWidth = 0.4
self.fontSize = 24
def addToPath( self, location, nextLine ):
"Add a point to travel and maybe extrusion."
if self.oldLocation == None:
return
beginningComplex = self.oldLocation.dropAxis( 2 )
endComplex = location.dropAxis( 2 )
colorName = 'gray'
if self.extruderActive:
colorName = self.colorNames[ self.extrusionNumber % len( self.colorNames ) ]
else:
splitLine = nextLine.split( ' ' )
firstWord = ''
if len( splitLine ) > 0:
firstWord = splitLine[ 0 ]
if firstWord != 'G1':
segment = endComplex - beginningComplex
segmentLength = abs( segment )
if segmentLength > 0.0:
truncation = 0.3 * min( segmentLength, self.extrusionWidth )
endComplex -= segment / segmentLength * truncation
self.vectorWindow.addColoredLine( self.scale * beginningComplex, self.scale * endComplex, colorName )
def initializeActiveLocation( self ):
"Set variables to default."
self.extruderActive = False
self.layerIndex = 0
self.oldLocation = None
def linearCorner( self, splitLine ):
"Update the bounding corners."
location = gcodec.getLocationFromSplitLine( self.oldLocation, splitLine )
if self.extruderActive:
self.cornerHigh = euclidean.getPointMaximum( self.cornerHigh, location )
self.cornerLow = euclidean.getPointMinimum( self.cornerLow, location )
self.oldLocation = location
def linearMove( self, splitLine, nextLine ):
"Get statistics for a linear move."
location = gcodec.getLocationFromSplitLine( self.oldLocation, splitLine )
self.addToPath( location, nextLine )
self.oldLocation = location
def parseCorner( self, line ):
"Parse a gcode line and use the location to update the bounding corners."
splitLine = line.split( ' ' )
if len( splitLine ) < 1:
return
firstWord = splitLine[ 0 ]
if firstWord == 'G1':
self.linearCorner( splitLine )
elif firstWord == 'M101':
self.extruderActive = True
elif firstWord == 'M103':
self.extruderActive = False
elif firstWord == '(':
self.extrusionWidth = gcodec.getDoubleAfterFirstLetter( splitLine[ 1 ] )
def parseGcode( self, gcodeText, vectorwritePreferences ):
"Parse gcode text and store the commented gcode."
self.initializeActiveLocation()
self.cornerHigh = Vec3( - 999999999.0, - 999999999.0, - 999999999.0 )
self.cornerLow = Vec3( 999999999.0, 999999999.0, 999999999.0 )
lines = gcodec.getTextLines( gcodeText )
for line in lines:
self.parseCorner( line )
self.initializeActiveLocation()
self.colorNames = [ 'brown', 'red', 'orange', 'yellow', 'green', 'blue', 'purple' ]
self.scale = vectorwritePreferences.pixelsWidthExtrusion.value / self.extrusionWidth
self.vectorWindow = VectorWindow()
self.vectorWindow.setPaneCorners( self.scale * self.cornerLow.dropAxis( 2 ), self.scale * self.cornerHigh.dropAxis( 2 ) )
for lineIndex in range( len( lines ) ):
line = lines[ lineIndex ]
nextLine = ''
nextIndex = lineIndex + 1
if nextIndex < len( lines ):
nextLine = lines[ nextIndex ]
self.parseLine( line, nextLine )
def parseLine( self, line, nextLine ):
"Parse a gcode line and add it to the commented gcode."
splitLine = line.split( ' ' )
if len( splitLine ) < 1:
return
firstWord = splitLine[ 0 ]
if firstWord == 'G1':
self.linearMove( splitLine, nextLine )
elif firstWord == 'M101':
self.extruderActive = True
self.extrusionNumber += 1
elif firstWord == 'M103':
self.extruderActive = False
elif firstWord == '(':
self.extrusionNumber = 0
if self.layerIndex > 0:
self.vectorWindow.addFontHeight( self.fontSize )
self.vectorWindow.addText( self.fontSize, 'Layer index ' + str( self.layerIndex ) + ', z ' + splitLine[ 1 ] )
self.layerIndex += 1
self.vectorWindow.addPane()
class VectorwritePreferences:
"A class to handle the vectorwrite preferences."
def __init__( self ):
"Set the default preferences, execute title & preferences filename."
#Set the default preferences.
self.pixelsWidthExtrusion = preferences.FloatPreference().getFromValue( 'Pixels for the Width of the Extrusion (ratio):', 10.0 )
self.writeSkeinforgeSVG = preferences.BooleanPreference().getFromValue( 'Write Scalable Vector Graphics for Skeinforge Chain:', True )
directoryRadio = []
self.directoryPreference = preferences.RadioLabel().getFromRadioLabel( 'Write Vector Graphics for All Unmodified Files in a Directory', 'File or Directory Choice:', directoryRadio, False )
self.filePreference = preferences.Radio().getFromRadio( 'Write Vector Graphics File', directoryRadio, True )
self.filenameInput = preferences.Filename().getFromFilename( [ ( 'Gcode text files', '*.gcode' ) ], 'Open File to Write Vector Graphics for', '' )
#Create the archive, title of the execute button, title of the dialog & preferences filename.
self.archive = [ self.pixelsWidthExtrusion, self.writeSkeinforgeSVG, self.directoryPreference, self.filePreference, self.filenameInput ]
self.executeTitle = 'Write Vector Graphics'
self.filenamePreferences = preferences.getPreferencesFilePath( 'vectorwrite.csv' )
self.filenameHelp = 'vectorwrite.html'
self.title = 'Vectorwrite Preferences'
def execute( self ):
"Write button has been clicked."
filenames = gcodec.getGcodeDirectoryOrFile( self.directoryPreference.value, self.filenameInput.value, self.filenameInput.wasCancelled )
for filename in filenames:
writeVectorFile( filename )
def main( hashtable = None ):
"Display the vectorwrite dialog."
preferences.displayDialog( VectorwritePreferences() )
if __name__ == "__main__":
main()