Making stl files with python for 3d printing
Poul Riis
priisdk at gmail.com
Sun Nov 13 17:56:01 EST 2016
Below you can find my python code to make a vase for 3D-printing.
The vase looks nice on my screen so the vertices and the faces seem to be perfect.
However, when sending the .stl file produced to a 3D-printer the vase comes out as a filled solid - no room for water and flowers!
I have tried to slice the vase the the program "Cura". It seems that the slices are full disks, not rings as intended, at some values of z but far from all.
I don't expect anybody to read the full program (I'm a very poor programmer) but my hope is that someone can give a hint as to how I can improve the writing of the .stl file.
Poul Riis
#!/usr/bin/env python
#coding:utf-8
# Purpose: Export 3D objects, build of faces with 3 or 4 vertices, as ASCII or Binary STL file.
# License: MIT License
import struct
from tvtk.api import tvtk
from mayavi import mlab
from math import *
from sympy import *
ASCII_FACET = """facet normal 0 0 0
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"
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):
self.fp.write(ASCII_FACET.format(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
super(Binary_STL_Writer, self).__init__(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
data = [
0., 0., 0.,
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))
def example(fn):
def get_cube():
p=[]
nxy=24
nz=21#Must be odd
unit=10
h=2*unit
dh=h/nz
zbottom=-2*dh
thickness=0.3*unit
z=Symbol('z')
f=1*(1+sin((z/h)**2*1*pi)/8)*exp(z/h/2)*unit#1*
#f=(1+z/h)*unit
flambdified = lambdify(z, f)
fdiff=f.diff(z)
fdifflambdified = lambdify(z, fdiff)
rinner0=10
rinner=rinner0
router0=rinner0+thickness
router=router0
deltar=1
deltaphi=2*pi/nxy
deltaphih=deltaphi/2
nxyz=nxy*nz
npts=0
#Inner:
for j in range(0,nz+1):
zact=j*dh
ract=flambdified(zact)
phiact=j%2*(-deltaphih)
for i in range(0,nxy):
p.append((ract*cos(phiact),ract*sin(phiact),zact))
phiact=phiact+deltaphi
npts=npts+1
npts1=npts
#Middle of upper rim:
phiact=0
ract=flambdified(zact)
a=fdifflambdified(zact)
b=sqrt(1+a*a)
k=thickness/b/2
for i in range(0,nxy):
cosphi=cos(phiact)
sinphi=sin(phiact)
dx=k*cosphi
dy=k*sinphi
dz=-k*a
p.append((ract*cosphi+dx,ract*sinphi+dy,zact+dz))
phiact=phiact+deltaphi
npts1=npts1+1
#Outer:
for j in range(-1,nz+2):
zact=(nz-j-1)*dh
ract=flambdified(zact)
a=fdifflambdified(zact)
b=sqrt(1+a*a)
k=thickness/b
phiact=(j-0)%2*(-deltaphih)
for i in range(0,nxy):
cosphi=cos(phiact)
sinphi=sin(phiact)
dx=k*cosphi
dy=k*sinphi
dz=-k*a
p.append((ract*cosphi+dx,ract*sinphi+dy,zact+dz))
phiact=phiact+deltaphi
npts1=npts1+1
#Center of bottom:
p.append((0,0,-thickness))
parray=[]
#Inner:
for j in range(0,nz*2+4,2):
for i in range(0,nxy):
i0=i%nxy+j*nxy
i1=(i+1)%nxy+j*nxy
i2=(i+1)%nxy+nxy+j*nxy
i3=i%nxy+nxy+j*nxy
parray.append([p[i0],p[i1],p[i2],p[i3]])
for i in range(0,nxy):
i0=(i+1)%nxy+nxy+j*nxy
i1=i%nxy+nxy+j*nxy
i2=i%nxy+nxy+nxy+j*nxy
i3=(i+1)%nxy+nxy+nxy+j*nxy
parray.append([p[i0],p[i1],p[i2],p[i3]])
#Inner bottom:
for i in range(0,nxy):
parray.append([(0,0,0),p[i%nxy],p[(i+1)%nxy]])
#Outer bottom:
for i in range(0,nxy):
parray.append([(0,0,zbottom),p[npts1-i%nxy-1],p[npts1-(i+1)%nxy-1]])
return parray
filename=fn+'.stl'
with open(filename, 'wb') as fp:
writer = Binary_STL_Writer(fp)
writer.add_faces(get_cube())
writer.close()
print(filename,' saved.')
# Finally the plotting:
print('Finally the plotting....')
stlr = tvtk.STLReader()
stlr.file_name = file_name=filename
stlr.update()
stld = stlr.output
fig = mlab.figure(bgcolor=(1, 1, 1), fgcolor=(0, 0, 0))
surf = mlab.pipeline.surface(stld, opacity=1, color=(0.3, 0.8, 0.7))
edge = mlab.pipeline.extract_edges(surf)
edge_surf = mlab.pipeline.surface(edge, opacity=.1, color=(1,0,0))
if __name__ == '__main__':
example('vase_simple')
More information about the Python-list
mailing list