-
Notifications
You must be signed in to change notification settings - Fork 16
/
STLFile.py
executable file
·139 lines (114 loc) · 4.78 KB
/
STLFile.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
from OpenGL.GL import *
from OpenGL.GLU import *
import struct
#class for a 3d point
class createpoint:
def __init__(self,p,c=(1,0,0)):
self.point_size=0.5
self.color=c
self.x=p[0]
self.y=p[1]
self.z=p[2]
def glvertex(self):
glVertex3f(self.x,self.y,self.z)
#class for a 3d face on a model
class createtriangle:
points=None
normal=None
def __init__(self,p1,p2,p3,n=None):
#3 points of the triangle
self.points=createpoint(p1),createpoint(p2),createpoint(p3)
#triangles normal
self.normal=createpoint(self.calculate_normal(self.points[0],self.points[1],self.points[2]))#(0,1,0)#
#calculate vector / edge
def calculate_vector(self,p1,p2):
return -p1.x+p2.x,-p1.y+p2.y,-p1.z+p2.z
def calculate_normal(self,p1,p2,p3):
a=self.calculate_vector(p3,p2)
b=self.calculate_vector(p3,p1)
#calculate the cross product returns a vector
return self.cross_product(a,b)
def cross_product(self,p1,p2):
return (p1[1]*p2[2]-p2[1]*p1[2]) , (p1[2]*p2[0])-(p2[2]*p1[0]) , (p1[0]*p2[1])-(p2[0]*p1[1])
class loader:
def __init__(self, filename):
self.model=[]
self.load_stl(filename)
#return the faces of the triangles
def get_triangles(self):
if self.model:
for face in self.model:
yield face
#draw the models faces
def draw(self):
glBegin(GL_TRIANGLES)
for tri in self.get_triangles():
glNormal3f(tri.normal.x,tri.normal.y,tri.normal.z)
glVertex3f(tri.points[0].x,tri.points[0].y,tri.points[0].z)
glVertex3f(tri.points[1].x,tri.points[1].y,tri.points[1].z)
glVertex3f(tri.points[2].x,tri.points[2].y,tri.points[2].z)
glEnd()
#load stl file detects if the file is a text file or binary file
def load_stl(self,filename):
#read start of file to determine if its a binay stl file or a ascii stl file
fp=open(filename,'rb')
h=fp.read(80)
type=h[0:5]
fp.close()
if type==b'solid':
# print ("reading stl file "+str(filename))
self.load_text_stl(filename)
else:
# print ("reading binary stl file "+str(filename))
self.load_binary_stl(filename)
#read text stl match keywords to grab the points to build the model
def load_text_stl(self,filename):
fp=open(filename,'r')
for line in fp.readlines():
words=line.split()
if len(words)>0:
if words[0]=='solid':
self.name=words[1]
if words[0]=='facet':
center=[0.0,0.0,0.0]
triangle=[]
normal=(eval(words[2]),eval(words[3]),eval(words[4]))
if words[0]=='vertex':
triangle.append((eval(words[1]),eval(words[2]),eval(words[3])))
if words[0]=='endloop':
#make sure we got the correct number of values before storing
if len(triangle)==3:
self.model.append(createtriangle(triangle[0],triangle[1],triangle[2],normal))
fp.close()
#load binary stl file check wikipedia for the binary layout of the file
#we use the struct library to read in and convert binary data into a format we can use
def load_binary_stl(self,filename):
fp=open(filename,'rb')
h=fp.read(80)
l=struct.unpack('I',fp.read(4))[0]
count=0
while True:
try:
p=fp.read(12)
if len(p)==12:
n=struct.unpack('f',p[0:4])[0],struct.unpack('f',p[4:8])[0],struct.unpack('f',p[8:12])[0]
p=fp.read(12)
if len(p)==12:
p1=struct.unpack('f',p[0:4])[0],struct.unpack('f',p[4:8])[0],struct.unpack('f',p[8:12])[0]
p=fp.read(12)
if len(p)==12:
p2=struct.unpack('f',p[0:4])[0],struct.unpack('f',p[4:8])[0],struct.unpack('f',p[8:12])[0]
p=fp.read(12)
if len(p)==12:
p3=struct.unpack('f',p[0:4])[0],struct.unpack('f',p[4:8])[0],struct.unpack('f',p[8:12])[0]
new_tri=(n,p1,p2,p3)
if len(new_tri)==4:
tri=createtriangle(p1,p2,p3,n)
self.model.append(tri)
count+=1
fp.read(2)
if len(p)==0:
break
except EOFError:
break
fp.close()