chiark / gitweb /
plugins: Support user configuration of default values
[cura.git] / Cura / util / meshLoaders / stl.py
1 """
2 STL file mesh loader.
3 STL is the most common file format used for 3D printing right now.
4 STLs come in 2 flavors.
5         Binary, which is easy and quick to read.
6         Ascii, which is harder to read, as can come with windows, mac and unix style newlines.
7         The ascii reader has been designed so it has great compatibility with all kinds of formats or slightly broken exports from tools.
8
9 This module also contains a function to save objects as an STL file.
10
11 http://en.wikipedia.org/wiki/STL_(file_format)
12 """
13 __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
14
15 import sys
16 import os
17 import struct
18 import time
19
20 from Cura.util import printableObject
21
22 def _loadAscii(m, f):
23         cnt = 0
24         for lines in f:
25                 for line in lines.split('\r'):
26                         if 'vertex' in line:
27                                 cnt += 1
28         m._prepareFaceCount(int(cnt) / 3)
29         f.seek(5, os.SEEK_SET)
30         cnt = 0
31         data = [None,None,None]
32         for lines in f:
33                 for line in lines.split('\r'):
34                         if 'vertex' in line:
35                                 data[cnt] = line.replace(',', '.').split()[1:]
36                                 cnt += 1
37                                 if cnt == 3:
38                                         m._addFace(float(data[0][0]), float(data[0][1]), float(data[0][2]), float(data[1][0]), float(data[1][1]), float(data[1][2]), float(data[2][0]), float(data[2][1]), float(data[2][2]))
39                                         cnt = 0
40
41 def _loadBinary(m, f):
42         #Skip the header
43         f.read(80-5)
44         faceCount = struct.unpack('<I', f.read(4))[0]
45         m._prepareFaceCount(faceCount)
46         for idx in xrange(0, faceCount):
47                 data = struct.unpack("<ffffffffffffH", f.read(50))
48                 m._addFace(data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10], data[11])
49
50 def loadScene(filename):
51         obj = printableObject.printableObject(filename)
52         m = obj._addMesh()
53
54         f = open(filename, "rb")
55         if f.read(5).lower() == "solid":
56                 _loadAscii(m, f)
57                 if m.vertexCount < 3:
58                         f.seek(5, os.SEEK_SET)
59                         _loadBinary(m, f)
60         else:
61                 _loadBinary(m, f)
62         f.close()
63         obj._postProcessAfterLoad()
64         return [obj]
65
66 def saveScene(filename, objects):
67         f = open(filename, 'wb')
68         saveSceneStream(f, objects)
69         f.close()
70
71 def saveSceneStream(stream, objects):
72         #Write the STL binary header. This can contain any info, except for "SOLID" at the start.
73         stream.write(("CURA BINARY STL EXPORT. " + time.strftime('%a %d %b %Y %H:%M:%S')).ljust(80, '\000'))
74
75         vertexCount = 0
76         for obj in objects:
77                 for m in obj._meshList:
78                         vertexCount += m.vertexCount
79
80         #Next follow 4 binary bytes containing the amount of faces, and then the face information.
81         stream.write(struct.pack("<I", int(vertexCount / 3)))
82         for obj in objects:
83                 for m in obj._meshList:
84                         vertexes = m.getTransformedVertexes(True)
85                         for idx in xrange(0, m.vertexCount, 3):
86                                 v1 = vertexes[idx]
87                                 v2 = vertexes[idx+1]
88                                 v3 = vertexes[idx+2]
89                                 stream.write(struct.pack("<fff", 0.0, 0.0, 0.0))
90                                 stream.write(struct.pack("<fff", v1[0], v1[1], v1[2]))
91                                 stream.write(struct.pack("<fff", v2[0], v2[1], v2[2]))
92                                 stream.write(struct.pack("<fff", v3[0], v3[1], v3[2]))
93                                 stream.write(struct.pack("<H", 0))