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 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
|
from __future__ import absolute_import
import math
import struct
ASCII_FACET = """facet normal {normal[0]:.4f} {normal[1]:.4f} {normal[2]:.4f}
outer loop
vertex {face[0][0]:.4f} {face[0][1]:.4f} {face[0][2]:.4f}
vertex {face[1][0]:.4f} {face[1][1]:.4f} {face[1][2]:.4f}
vertex {face[2][0]:.4f} {face[2][1]:.4f} {face[2][2]:.4f}
endloop
endfacet
"""
BINARY_HEADER ="80sI"
BINARY_FACET = "12fH"
def crossproduct(u,v):
s1 = u[1]*v[2] - u[2]*v[1]
s2 = u[2]*v[0] - u[0]*v[2]
s3 = u[0]*v[1] - u[1]*v[0]
return [s1, s2, s3]
def norm(v):
return math.sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2])
def normalize(v):
m = norm(v)
return [v[0]/m, v[1]/m, v[2]/m]
def normalto(u,v):
return normalize(crossproduct(u,v))
def diff(u,v):
return [u[0]-v[0], u[1]-v[1], u[2]-v[2]]
#functions for calculation of the normal vector (right-thumb-rule)
def crossProduct(a, b):
#calculate cross product of two threedimensional vectors
if (len(a)!=3) or (len(b)!=3):
raise ValueError('unvalid value')
return [a[1]*b[2] - a[2]*b[1], a[2]*b[0] - a[0]*b[2], a[0]*b[1] - a[1]*b[0]]
def diff(v1,v2):
#substracting one list from another
if (len(v1)!=3) or (len(v2)!=3):
raise ValueError('unvalid value')
return [v1[0]-v2[0],v1[1]-v2[1],v1[2]-v2[2]]
def normal(v1,v2,v3):
#calculate normal vector on triangle spanned by the three vertices
#tells in which direction the plane looks "right-thumb-rule"
if (len(v1)!=3) or (len(v2)!=3) or (len(v2)!=3):
raise ValueError('unvalid value')
n=crossProduct(diff(v2,v1),diff(v3,v1))
absolut=0
for i in n:
if i>=0:
absolut+=i
else:
absolut-=i
if absolut == 0:
#print "this should not have happened!"
return n
else :
return [n[0]/absolut,n[1]/absolut,n[2]/absolut]
#simple function to create sets of three vertices
def triangulate(vertices):
n=len(vertices)
if(n==3):
return vertices
elif n < 3:
facets = triangulate(facet)
self.add_facets(facets)
else:
raise ValueError('wrong number of vertices')
def add_facets(self, facets):
#print "add %d facets" % len(facets)
for facet in facets:
self.add_facet(facet)
def extrude(self,bottom,height):
if len(bottom) < 3 :
raise ValueError('not a polygon')
else :
top = []
for vertice in bottom :
top.append([vertice[0],vertice[1],vertice[2]+height])
bottom.reverse()
self.add_facet(bottom)
bottom.reverse()
for i in range(0,len(bottom)-1) :
self.add_facet([bottom[i],bottom[i+1],top[i+1],top[i]])
self.add_facet([bottom[len(bottom)-1],bottom[0],top[0],top[len(bottom)-1]])
self.add_facet(top)
class ASCII_STL_Writer:
""" Export 3D objects build of 3 or 4 vertices as ASCII STL file.
"""
def __init__(self, stream):
self.fp = stream
self._write_header()
def _write_header(self):
self.fp.write("solid python\n")
def close(self):
self.fp.write("endsolid python\n")
def _write(self, face):
n = normalto(diff(face[0],face[1]),diff(face[1],face[2]))
self.fp.write(ASCII_FACET.format(normal=n,face=face))
def _split(self, face):
p1, p2, p3, p4 = face
return (p1, p2, p3), (p3, p4, p1)
def add_face(self, face):
""" Add one face with 3 or 4 vertices. """
if len(face) == 4:
face1, face2 = self._split(face)
self._write(face1)
self._write(face2)
elif len(face) == 3:
self._write(face)
else:
raise ValueError('only 3 or 4 vertices for each face')
def add_faces(self, faces):
""" Add many faces. """
for face in faces:
self.add_face(face)
class Binary_STL_Writer(ASCII_STL_Writer):
""" Export 3D objects build of 3 or 4 vertices as binary STL file.
"""
def __init__(self, stream):
self.counter = 0
ASCII_STL_Writer.__init__(self,stream)
def close(self):
self._write_header()
def _write_header(self):
self.fp.seek(0)
self.fp.write(struct.pack(BINARY_HEADER, b'Python Binary STL Writer', self.counter))
def _write(self, face):
self.counter += 1
n = normalto(diff(face[0],face[1]),diff(face[1],face[2]))
data = [
n[0], n[1], n[2],
face[0][0], face[0][1], face[0][2],
face[1][0], face[1][1], face[1][2],
face[2][0], face[2][1], face[2][2],
0
]
self.fp.write(struct.pack(BINARY_FACET, *data))
|