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