2 This page is in the table of contents.
3 The slc.py script is an import translator plugin to get a carving from an [http://rapid.lpt.fi/archives/rp-ml-1999/0713.html slc file].
5 An import plugin is a script in the interpret_plugins folder which has the function getCarving. It is meant to be run from the interpret tool. To ensure that the plugin works on platforms which do not handle file capitalization properly, give the plugin a lower case name.
7 The getCarving function takes the file name of an slc file and returns the carving.
12 from __future__ import absolute_import
13 #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.
16 from fabmetheus_utilities.vector3 import Vector3
17 from fabmetheus_utilities import euclidean
18 from fabmetheus_utilities import gcodec
19 from fabmetheus_utilities import svg_writer
20 from struct import unpack
25 __author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
26 __credits__ = 'Nophead <http://hydraraptor.blogspot.com/>\nArt of Illusion <http://www.artofillusion.org/>'
27 __date__ = '$Date: 2008/21/04 $'
28 __license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
31 def getCarving(fileName=''):
32 "Get the triangle mesh for the slc file."
33 carving = SLCCarving()
34 carving.readFile(fileName)
37 def getLittleEndianFloatGivenFile( file ):
38 "Get little endian float given a file."
39 return unpack('<f', file.read(4) )[0]
41 def getLittleEndianUnsignedLongGivenFile( file ):
42 "Get little endian float given a file."
43 return unpack('<L', file.read(4) )[0]
45 def getPointsFromFile( numPoints, file ):
46 "Process the vertice points for a given boundary."
48 for pointIndex in xrange( numPoints ):
49 x = getLittleEndianFloatGivenFile( file )
50 y = getLittleEndianFloatGivenFile( file )
51 points.append( complex(x, y) )
54 def readHeader( file ):
55 "Read the slc header."
56 while ord( file.read( 1 ) ) != 0x1A:
60 class SampleTableEntry:
62 def __init__( self, file ):
63 "Read in the sampling table section. It contains a table length (byte) and the table entries."
64 self.min_z_level = getLittleEndianFloatGivenFile( file )
65 self.layer_thickness = getLittleEndianFloatGivenFile( file )
66 self.beam_comp = getLittleEndianFloatGivenFile( file )
67 getLittleEndianFloatGivenFile( file )
70 "Get the string representation of this sample table entry."
71 return '%s, %s, %s' % ( self.min_z_level, self.layer_thickness, self.beam_comp )
78 self.layerHeight = None
80 self.maximumZ = - 987654321.0
81 self.minimumZ = 987654321.0
84 "Get the string representation of this carving."
85 return self.getCarvedSVG()
87 def addXML(self, depth, output):
88 "Add xml for this object."
89 xml_simple_writer.addXMLFromObjects(depth, self.loopLayers, output)
91 def getCarveBoundaryLayers(self):
92 "Get the boundary layers."
93 return self.loopLayers
95 def getCarveCornerMaximum(self):
96 "Get the corner maximum of the vertexes."
97 return self.cornerMaximum
99 def getCarveCornerMinimum(self):
100 "Get the corner minimum of the vertexes."
101 return self.cornerMinimum
103 def getCarvedSVG(self):
104 "Get the carved svg text."
105 if len(self.loopLayers) < 1:
107 decimalPlaces = max(0, 2 - int(math.floor(math.log10(self.layerHeight))))
108 self.svgWriter = svg_writer.SVGWriter(True, self.cornerMaximum, self.cornerMinimum, decimalPlaces, self.layerHeight)
109 return self.svgWriter.getReplacedSVGTemplate(self.fileName, self.loopLayers, 'basic')
111 def getCarveLayerHeight(self):
112 "Get the layer height."
113 return self.layerHeight
115 def getFabmetheusXML(self):
116 "Return the fabmetheus XML."
119 def getInterpretationSuffix(self):
120 "Return the suffix for a carving."
123 def processContourLayers( self, file ):
124 "Process a contour layer at a time until the top of the part."
126 minLayer = getLittleEndianFloatGivenFile( file )
127 numContours = getLittleEndianUnsignedLongGivenFile( file )
128 if numContours == 0xFFFFFFFF:
130 loopLayer = euclidean.LoopLayer( minLayer )
131 self.loopLayers.append( loopLayer )
132 for contourIndex in xrange( numContours ):
133 numPoints = getLittleEndianUnsignedLongGivenFile( file )
134 numGaps = getLittleEndianUnsignedLongGivenFile( file )
136 loopLayer.loops.append( getPointsFromFile( numPoints, file ) )
138 def readFile( self, fileName ):
139 "Read SLC and store the layers."
140 self.fileName = fileName
141 pslcfile = open( fileName, 'rb')
142 readHeader( pslcfile )
143 pslcfile.read( 256 ) #Go past the 256 byte 3D Reserved Section.
144 self.readTableEntry( pslcfile )
145 self.processContourLayers( pslcfile )
147 self.cornerMaximum = Vector3(-987654321.0, -987654321.0, self.maximumZ)
148 self.cornerMinimum = Vector3(987654321.0, 987654321.0, self.minimumZ)
149 for loopLayer in self.loopLayers:
150 for loop in loopLayer.loops:
152 pointVector3 = Vector3(point.real, point.imag, loopLayer.z)
153 self.cornerMaximum.maximize(pointVector3)
154 self.cornerMinimum.minimize(pointVector3)
155 halfLayerThickness = 0.5 * self.layerHeight
156 self.cornerMaximum.z += halfLayerThickness
157 self.cornerMinimum.z -= halfLayerThickness
159 def readTableEntry( self, file ):
160 "Read in the sampling table section. It contains a table length (byte) and the table entries."
161 tableEntrySize = ord( file.read( 1 ) )
162 if tableEntrySize == 0:
163 print("Sampling table size is zero!")
165 for index in xrange( tableEntrySize ):
166 sampleTableEntry = SampleTableEntry( file )
167 self.layerHeight = sampleTableEntry.layerHeight
169 def setCarveImportRadius( self, importRadius ):
170 "Set the import radius."
173 def setCarveIsCorrectMesh( self, isCorrectMesh ):
174 "Set the is correct mesh flag."
177 def setCarveLayerHeight( self, layerHeight ):
178 "Set the layer height."
183 "Display the inset dialog."
184 if len(sys.argv) > 1:
185 getCarving(' '.join(sys.argv[1 :]))
187 if __name__ == "__main__":