chiark / gitweb /
Add uppercase STL and HEX to file dialog filters for linux/MacOS
[cura.git] / Cura / cura_sf / fabmetheus_utilities / fabmetheus_tools / interpret_plugins / stl.py
1 """
2 This page is in the table of contents.
3 The stl.py script is an import translator plugin to get a carving from an stl 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 stl file and returns the carving.
8
9 STL is an inferior triangle surface format, described at:
10 http://en.wikipedia.org/wiki/STL_(file_format)
11
12 A good triangle surface format is the GNU Triangulated Surface format which is described at:
13 http://gts.sourceforge.net/reference/gts-surfaces.html#GTS-SURFACE-WRITE
14
15 """
16
17
18 from __future__ import absolute_import
19 #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.
20 import __init__
21
22 from fabmetheus_utilities.geometry.geometry_tools import face
23 from fabmetheus_utilities.geometry.solids import triangle_mesh
24 from fabmetheus_utilities.vector3 import Vector3
25 from fabmetheus_utilities import archive
26 from fabmetheus_utilities import gcodec
27 from struct import unpack
28
29 __author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
30 __credits__ = 'Nophead <http://hydraraptor.blogspot.com/>\nArt of Illusion <http://www.artofillusion.org/>'
31 __date__ = '$Date: 2008/21/04 $'
32 __license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
33
34
35 def addFacesGivenBinary( stlData, triangleMesh, vertexIndexTable ):
36         "Add faces given stl binary."
37         numberOfVertexes = ( len( stlData ) - 84 ) / 50
38         vertexes = []
39         for vertexIndex in xrange( numberOfVertexes ):
40                 byteIndex = 84 + vertexIndex * 50
41                 vertexes.append( getVertexGivenBinary( byteIndex + 12, stlData ) )
42                 vertexes.append( getVertexGivenBinary( byteIndex + 24, stlData ) )
43                 vertexes.append( getVertexGivenBinary( byteIndex + 36, stlData ) )
44         addFacesGivenVertexes( triangleMesh, vertexIndexTable, vertexes )
45
46 def addFacesGivenText( stlText, triangleMesh, vertexIndexTable ):
47         "Add faces given stl text."
48         lines = archive.getTextLines( stlText )
49         vertexes = []
50         for line in lines:
51                 if line.find('vertex') != - 1:
52                         vertexes.append( getVertexGivenLine(line) )
53         addFacesGivenVertexes( triangleMesh, vertexIndexTable, vertexes )
54
55 def addFacesGivenVertexes( triangleMesh, vertexIndexTable, vertexes ):
56         "Add faces given stl text."
57         for vertexIndex in xrange( 0, len(vertexes), 3 ):
58                 triangleMesh.faces.append( getFaceGivenLines( triangleMesh, vertexIndex, vertexIndexTable, vertexes ) )
59
60 def getCarving(fileName=''):
61         "Get the triangle mesh for the stl file."
62         if fileName == '':
63                 return None
64         stlData = archive.getFileText(fileName, True, 'rb')
65         if stlData == '':
66                 return None
67         triangleMesh = triangle_mesh.TriangleMesh()
68         vertexIndexTable = {}
69         numberOfVertexStrings = stlData.count('vertex')
70         requiredVertexStringsForText = max( 2, len( stlData ) / 8000 )
71         if numberOfVertexStrings > requiredVertexStringsForText:
72                 addFacesGivenText( stlData, triangleMesh, vertexIndexTable )
73         else:
74 #       A binary stl should never start with the word "solid".  Because this error is common the file is been parsed as binary regardless.
75                 addFacesGivenBinary( stlData, triangleMesh, vertexIndexTable )
76         return triangleMesh
77
78 def getFaceGivenLines( triangleMesh, vertexStartIndex, vertexIndexTable, vertexes ):
79         "Add face given line index and lines."
80         faceGivenLines = face.Face()
81         faceGivenLines.index = len( triangleMesh.faces )
82         for vertexIndex in xrange( vertexStartIndex, vertexStartIndex + 3 ):
83                 vertex = vertexes[vertexIndex]
84                 vertexUniqueIndex = len( vertexIndexTable )
85                 if str(vertex) in vertexIndexTable:
86                         vertexUniqueIndex = vertexIndexTable[ str(vertex) ]
87                 else:
88                         vertexIndexTable[ str(vertex) ] = vertexUniqueIndex
89                         triangleMesh.vertexes.append(vertex)
90                 faceGivenLines.vertexIndexes.append( vertexUniqueIndex )
91         return faceGivenLines
92
93 def getFloat(floatString):
94         "Get the float, replacing commas if necessary because an inferior program is using a comma instead of a point for the decimal point."
95         try:
96                 return float(floatString)
97         except:
98                 return float( floatString.replace(',', '.') )
99
100 def getFloatGivenBinary( byteIndex, stlData ):
101         "Get vertex given stl vertex line."
102         return unpack('f', stlData[ byteIndex : byteIndex + 4 ] )[0]
103
104 def getVertexGivenBinary( byteIndex, stlData ):
105         "Get vertex given stl vertex line."
106         return Vector3( getFloatGivenBinary( byteIndex, stlData ), getFloatGivenBinary( byteIndex + 4, stlData ), getFloatGivenBinary( byteIndex + 8, stlData ) )
107
108 def getVertexGivenLine(line):
109         "Get vertex given stl vertex line."
110         splitLine = line.split()
111         return Vector3( getFloat(splitLine[1]), getFloat( splitLine[2] ), getFloat( splitLine[3] ) )