chiark / gitweb /
23b2d190e901392aef062d5da576eb6fa84fbb81
[cura.git] / Cura / fabmetheus_utilities / fabmetheus_tools / interpret_plugins / slc.py
1 """
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].
4
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.
6
7 The getCarving function takes the file name of an slc file and returns the carving.
8
9 """
10
11
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.
14 import __init__
15
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
21 import math
22 import sys
23
24
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'
29
30
31 def getCarving(fileName=''):
32         "Get the triangle mesh for the slc file."
33         carving = SLCCarving()
34         carving.readFile(fileName)
35         return carving
36
37 def getLittleEndianFloatGivenFile( file ):
38         "Get little endian float given a file."
39         return unpack('<f', file.read(4) )[0]
40
41 def getLittleEndianUnsignedLongGivenFile( file ):
42         "Get little endian float given a file."
43         return unpack('<L', file.read(4) )[0]
44
45 def getPointsFromFile( numPoints, file ):
46         "Process the vertice points for a given boundary."
47         points = []
48         for pointIndex in xrange( numPoints ):
49                 x = getLittleEndianFloatGivenFile( file )
50                 y = getLittleEndianFloatGivenFile( file )
51                 points.append( complex(x, y) )
52         return points
53
54 def readHeader( file ):
55         "Read the slc header."
56         while ord( file.read( 1 ) ) != 0x1A:
57                 pass
58
59
60 class SampleTableEntry:
61         "Sample table entry."
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 )
68
69         def __repr__(self):
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 )
72
73
74 class SLCCarving:
75         "An slc carving."
76         def __init__(self):
77                 "Add empty lists."
78                 self.layerHeight = None
79                 self.loopLayers = []
80                 self.maximumZ = - 987654321.0
81                 self.minimumZ = 987654321.0
82         
83         def __repr__(self):
84                 "Get the string representation of this carving."
85                 return self.getCarvedSVG()
86
87         def addXML(self, depth, output):
88                 "Add xml for this object."
89                 xml_simple_writer.addXMLFromObjects(depth, self.loopLayers, output)
90
91         def getCarveBoundaryLayers(self):
92                 "Get the  boundary layers."
93                 return self.loopLayers
94
95         def getCarveCornerMaximum(self):
96                 "Get the corner maximum of the vertexes."
97                 return self.cornerMaximum
98
99         def getCarveCornerMinimum(self):
100                 "Get the corner minimum of the vertexes."
101                 return self.cornerMinimum
102
103         def getCarvedSVG(self):
104                 "Get the carved svg text."
105                 if len(self.loopLayers) < 1:
106                         return ''
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')
110
111         def getCarveLayerHeight(self):
112                 "Get the layer height."
113                 return self.layerHeight
114
115         def getFabmetheusXML(self):
116                 "Return the fabmetheus XML."
117                 return None
118
119         def getInterpretationSuffix(self):
120                 "Return the suffix for a carving."
121                 return 'svg'
122
123         def processContourLayers( self, file ):
124                 "Process a contour layer at a time until the top of the part."
125                 while True:
126                         minLayer = getLittleEndianFloatGivenFile( file )
127                         numContours = getLittleEndianUnsignedLongGivenFile( file )
128                         if numContours == 0xFFFFFFFF:
129                                 return
130                         loopLayer = euclidean.LoopLayer( minLayer )
131                         self.loopLayers.append( loopLayer )
132                         for contourIndex in xrange( numContours ):
133                                 numPoints = getLittleEndianUnsignedLongGivenFile( file )
134                                 numGaps = getLittleEndianUnsignedLongGivenFile( file )
135                                 if numPoints > 2:
136                                         loopLayer.loops.append( getPointsFromFile( numPoints, file ) )
137
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 )
146                 pslcfile.close()
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:
151                                 for point in loop:
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
158
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!")
164                         exit()
165                 for index in xrange( tableEntrySize ):
166                         sampleTableEntry = SampleTableEntry( file )
167                         self.layerHeight = sampleTableEntry.layerHeight
168
169         def setCarveImportRadius( self, importRadius ):
170                 "Set the import radius."
171                 pass
172
173         def setCarveIsCorrectMesh( self, isCorrectMesh ):
174                 "Set the is correct mesh flag."
175                 pass
176
177         def setCarveLayerHeight( self, layerHeight ):
178                 "Set the layer height."
179                 pass
180
181
182 def main():
183         "Display the inset dialog."
184         if len(sys.argv) > 1:
185                 getCarving(' '.join(sys.argv[1 :]))
186
187 if __name__ == "__main__":
188         main()