我想用Python编写一个脚本,该脚本可以根据Face Normal值条件在STL中生成面部组。例如,提供的是Stl的快照,不同的颜色表示包含满足我给定的脸部法线阈值的三角形脸部的脸部组。有没有简单的方法可以在python中做到这一点? Face Group STL
答案 0 :(得分:1)
我确定有一个python库可以加载stl文件,但是我总是编写自己的文件,因为文件格式非常简单(有关文件格式的说明,请参见Wikipedia article)。
这是我读取stl文件的代码:
import numpy as np
import struct
def Unique(inputList):
"""
Given an M x N list, this function gets the unique rows by treating all
M Ntuples as single objects. This function also returns the indexing
to convert the unique returned list back to the original non-unique list.
"""
hashTable=dict()
indexList=[]
uniqueList=[]
indx=0
for ntuple in inputList:
if not ntuple in hashTable:
hashTable[ntuple]=indx
indexList.append(indx)
uniqueList.append(ntuple)
indx+=1
else:
indexList.append(hashTable.get(ntuple))
return uniqueList, indexList
def IsBinarySTL(filename):
try:
with open(filename,'r') as f:
test=f.readline()
except UnicodeDecodeError:
return True
if len(test) < 5:
return True
elif test[0:5].lower() == 'solid':
return False # ASCII STL
else:
return True
def ReadSTL(filename):
""" Returns numpy arrays for vertices and facet indexing """
def GetListFromASCII(filename):
""" Returns vertex listing from ASCII STL file """
outputList=[]
with open(filename,'r') as f:
lines=[line.split() for line in f.readlines()]
for line in lines:
if line[0] == 'vertex':
outputList.append(tuple([float(x) for x in line[1:]]))
return outputList
def GetListFromBinary(filename):
""" Returns vertex listing from binary STL file """
outputList=[]
with open(filename,'rb') as f:
f.seek(80) # skip header
nFacets=struct.unpack('I',f.read(4))[0] # number of facets in piece
for i in range(nFacets):
f.seek(12,1) # skip normal
outputList.append(struct.unpack('fff',f.read(12))) # append each vertex triple to list (each facet has 3 vertices)
outputList.append(struct.unpack('fff',f.read(12)))
outputList.append(struct.unpack('fff',f.read(12)))
f.seek(2,1) # skip attribute
return outputList
if IsBinarySTL(filename):
vertexList = GetListFromBinary(filename)
else:
vertexList = GetListFromASCII(filename)
coords, tempindxs = Unique(vertexList)
indxs = list()
templist = list()
for i in range(len(tempindxs)):
if (i > 0 ) and not (i % 3):
indxs.append(templist)
templist = list()
templist.append(tempindxs[i])
indxs.append(templist)
return np.array(coords), np.array(indxs)
这是计算构面法线的代码(假设右手法则)
def GetNormals(vertices, facets):
""" Returns normals for each facet of mesh """
u = vertices[facets[:,1],:] - vertices[facets[:,0],:]
v = vertices[facets[:,2],:] - vertices[facets[:,0],:]
normals = np.cross(u,v)
norms = np.sqrt(np.sum(normals*normals, axis=1))
return normals/norms[:, np.newaxis]
最后,编写出stl文件的代码(假定每个构面的属性列表):
def WriteSTL(filename, vertices, facets, attributes, header):
"""
Writes vertices and facets to an stl file. Notes:
1.) header can not be longer than 80 characters
2.) length of attributes must be equal to length of facets
3.) attributes must be integers
"""
nspaces = 80 - len(header)
header += nspaces*'\0'
nFacets = np.shape(facets)[0]
stl = vertices[facets,:].tolist()
with open(filename,'wb') as f: # binary
f.write(struct.pack('80s', header.encode('utf-8'))) # header
f.write(struct.pack('I',nFacets)) # number of facets
for i in range(nFacets):
f.write(struct.pack('fff',0,0,0)) # normals set to 0
for j in range(3):
f.write(struct.pack('fff',stl[i][j][0], stl[i][j][1], stl[i][j][2])) # 3 vertices per facet
f.write(struct.pack("H", attributes[i])) # 2-byte attribute
将所有内容放在一起,您可以执行以下操作:
if __name__ == "__main__":
filename = "bunny.stl"
vertices, facets = ReadSTL(filename) # parse stl file
normals = GetNormals(vertices, facets) # compute normals
# Get some value related to normals
attributes = []
for i in range(np.shape(normals)[0]):
attributes.append(int(255*np.sum(normals[i])**2))
# Write new stl file
WriteSTL("output.stl", vertices, facets, attributes, "stlheader")
此代码段读取一个stl文件,计算法线,然后根据每个法线的平方和分配属性值(请注意,该属性必须是整数)。