Last active
April 8, 2019 03:34
-
-
Save mtao/7f79e94a2b1cfb864e9aee208d99a2f0 to your computer and use it in GitHub Desktop.
a simple stl to obj converter. currently doesn't support normals yet
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sys | |
import numpy as np | |
from struct import unpack | |
def strlist_to_vec(arr): | |
return tuple(float(x) for x in arr) | |
class Facet: | |
dtype = np.dtype([ | |
('N', np.float32,(3)), | |
('U', np.float32,(3)), | |
('V', np.float32,(3)), | |
('W', np.float32,(3)), | |
('A', '<i2',(1,) ) | |
]) | |
def __init__(self,fd, line=None): | |
self.binary = line is None | |
if self.binary: | |
self.parse_binary(fd) | |
else: | |
self.parse_ascii(line,fd) | |
def parse_binary(self,fd): | |
res = np.fromfile(fd,dtype=Facet.dtype, count=1) | |
self.normal = res['N'][0,:] | |
self.vertices = [ | |
tuple(v for v in res['U'][0,:]), | |
tuple(v for v in res['V'][0,:]), | |
tuple(v for v in res['W'][0,:]) | |
] | |
def parse_ascii(self,line,fd): | |
assert(line[0] == "facet") | |
assert(line[1] == "normal") | |
self.vertices = [] | |
self.normal = strlist_to_vec(line[2:]) | |
ol_line = fd.readline().split() | |
assert(ol_line[0] == "outer") | |
assert(ol_line[1] == "loop") | |
while fd: | |
line = fd.readline().split() | |
if len(line) == 0: | |
continue | |
elif line[0] == "endloop": | |
break | |
elif line[0] == "vertex": | |
self.vertices.append(strlist_to_vec(line[1:])) | |
def vertex_set(self): | |
return set(_ for _ in self.vertices) | |
def as_indices(self,indexer): | |
return np.array([indexer[v] for v in self.vertices]) | |
pass | |
class Solid: | |
def __init__(self,fd, line=None): | |
self.binary = line is None | |
if self.binary: | |
self.parse_binary(fd) | |
else: | |
self.parse_ascii(line,fd) | |
def parse_binary(self,fd): | |
num_elem = unpack("i",fd.read(4))[0] | |
self.facets = [Facet(fd) for _ in range(num_elem)] | |
def parse_ascii(self,line,fd): | |
assert(line[0] == "solid") | |
if len(line) > 1: | |
self.name = line[1] | |
self.facets = [] | |
while fd: | |
line = fd.readline().split() | |
if len(line) == 0: | |
continue | |
elif line[0] == "endsolid": | |
break | |
elif line[0] == "facet": | |
self.facets.append(Facet(fd,line)) | |
def vertex_map(self): | |
index = 0 | |
indexer = {} | |
for facet in self.facets: | |
for vertex in facet.vertex_set(): | |
if vertex not in indexer: | |
indexer[vertex] = index | |
index+=1 | |
return indexer | |
def VF(self): | |
indexer = self.vertex_map() | |
V = np.zeros((len(indexer),3)) | |
for v,i in indexer.items(): | |
V[i,:] = np.array(v) | |
F = np.vstack(f.as_indices(indexer) for f in self.facets) | |
return V,F | |
def N(self): | |
return np.vstack(f.normal for f in self.facets) | |
class STL: | |
def __is_binary__(self): | |
with open(self.__filename__,"rb") as fd: | |
return b'solid' != fd.read(5) | |
def __init__(self, filename): | |
self.__filename__ = filename | |
if self.__is_binary__(): | |
self.parse_binary() | |
else: | |
self.parse_ascii() | |
def parse_binary(self): | |
with open(self.__filename__,"rb") as fd: | |
header = fd.read(80) | |
self.solid = Solid(fd) | |
def parse_ascii(self): | |
with open(self.__filename__,"r") as fd: | |
line = fd.readline().split() | |
assert(line[0] == "solid") | |
self.solid = Solid(fd,line) | |
def VF(self): | |
return self.solid.VF() | |
def N(self): | |
return self.solid.N() | |
stl_fn = sys.argv[1] | |
if len(sys.argv) <= 2: | |
if stl_fn[-4:] == ".stl": | |
outfile = stl_fn[:-4] + ".obj" | |
else: | |
outfile = stl_fn + ".obj" | |
else: | |
outfile = sys.argv[2] | |
print("{} => {}".format(stl_fn,outfile)) | |
stl = STL(stl_fn) | |
V,F = stl.VF() | |
#for v in V: | |
# print("v " +" ".join(map(str,v))+"\n") | |
# | |
#for vn in stl.N(): | |
# print("vn " +" ".join(map(str,vn))+"\n") | |
# | |
#for i,f in enumerate(F): | |
# print("f " +" ".join(map(lambda x: "{}/{}".format(x,i+1),f+1))+"\n") | |
with open(outfile,"w") as fd: | |
for v in V: | |
fd.write("v " +" ".join(map(str,v))+"\n") | |
for vn in stl.N(): | |
fd.write("vn " +" ".join(map(str,vn))+"\n") | |
for i,f in enumerate(F): | |
fd.write("f " +" ".join(map(str,f+1))+"\n") | |
#fd.write("f " +" ".join(map(lambda x: "{}/{}".format(x,i+1),f+1))+"\n") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment