Function Based 3-D Solid Modeller

Aaron Schilling, Fareed Faghih, Marcus Lew

Math480B Final Project -- 6/4/2010

3D Model of a Jack in a Cube

3D Modelling Software in action

Self-Replicating RepRap 3D Printer

 

 

Commercial Z406 3D printer

Example 3D scan and 3D print


{{{id=1| %auto #Define Variables x,y,z = var('x, y, z') #Transformations: Mathematical functions to change the geometrical size or location of solids. Includes translations, scaling, reflection and rotation. #Translations: Movement in the specific direction def TransX(a,tx) : return a.substitute(x=(x-tx)) def TransY(a,ty) : return a.substitute(y=(y-ty)) def TransZ(a,tz) : return a.substitute(z=(z-tz)) #Scaling: Size factor change in specific direction def ScaleX(a,sx) : return a.substitute(x=(x/sx)) def ScaleY(a,sy) : return a.substitute(y=(y/sy)) def ScaleZ(a,sz) : return a.substitute(z=(z/sz)) def ScaleXYZ(a,s) : return a.substitute(x=(x/s),y=(y/s),z=(z/s)) #Reflection: Reflects across specific plane def ReflectXY(a) : return a.substitute(z=(-z)) def ReflectZX(a) : return a.substitute(y=(-y)) def ReflectYZ(a) : return a.substitute(x=(-x)) #Rotation: Turning in specific plane def DegToRad(a) : return (pi*a/180) def RotateRX(a,r) : return a.substitute(y=(y*cos(r) - z*sin(r)), z=(y*sin(r) + z*cos(r))) def RotateRY(a,r) : return a.substitute(x=(x*cos(r) + z*sin(r)), z=(-x*sin(r) + z*cos(r))) def RotateRZ(a,r) : return a.substitute(x=(x*cos(r) + y*sin(r)), y=(-x*sin(r) + y*cos(r))) def RotateX(a,d) : return RotateRX(a, DegToRad(d)) def RotateY(a,d) : return RotateRY(a, DegToRad(d)) def RotateZ(a,d) : return RotateRZ(a, DegToRad(d)) # Simpler Plot Function: Reduces implicit_plot3d to a simpler more practical plotter def Plot3d (sld,size,pts) : return implicit_plot3d(sld, (x, -size, size), (y, -size, size), (z, -size, size), plot_points=pts) # Boolean Operators: For shape interactions def Union(a,b) : return Min(a,b) def Intersect(a,b) : return Max(a,b) def Subtract(a,b) : return Max(a,-b) def Morph (a,b,t) : return ((b-a)*t+a) def Blend (a,b,l) : return (a*b)-l def Combine (a,b,k) : return k*(a+b) Max(a,b) = (a + b + abs(a - b)) / 2 Min(a,b) = (a + b - abs(a - b)) / 2 # Primitives and Shapes: Defines the specific building blocks which can be pieced together or transformed to form the desired object. Adapted from w3dsurf and wolfram mathworld def Sphere (a) : return (x^2+y^2+z^2-a^2) def Cube(h) : return (Max(Max(abs(x/(h/2)), abs(y/(h/2))), abs(z/(h/2))) - 1) def Prism(a,b,c) : return (Max(Max(abs(x/(a/2)), abs(y/(b/2))), abs(z/(c/2))) - 1) def Torus(a,b) : return ((a-sqrt(x^2+y^2)^2+z^2-b^2)) def Cyyl(a,b,c) : return Intersect(((x^2/a)+(y^2/b)-1),Close(z,c)) def Cone(a,b,c) : return Intersect(((c*sqrt((x^2/a^2)+(y^2/b^2)))-z),Close(z,c)) def Ellip(a,b,c) : return ((x^2/a^2)+(y^2/b^2)+(z^2/c^2)-1) def Para (a,b,c) : return (Max((x^2/a^2+y^2/b^2-c*z),z)-1) def Close(a,b) : return (abs(a/(b/2))-1) def HSpace (h) : return z-h def Tetrahedral (a,b,c) : return ((x^2 + y^2 + z^2)^2 + a*x*y*z - b*(x^2 + y^2 + z^2) + c) def Sinus (r,h) : return (sin(pi*(x^2+y^2-r^2))/2+h*z) def Bug (a,b,c) : return ((x*cos(b*y)-z*sin(b*y))+a)^2+(y/c)^2+(x*sin(b*y)+z*cos(b*y))^2 - 1 def Drope (h) : return (z - h*x*exp(-x^2-y^2)) def Heart (a,b,c,d,e) : return (a*(x^2)+b*(y^2)+c*(z^2)-1)^3-d*(x^2)*(z^3)-e*(y^2)*(z^3) def surface_to_stl_filesave(surface,filename): # Return an STL representation of the surface to a file. # Original work by Christopher Olah and later modified to write to a # file. # # INPUT: # - `surface` -- any surface, eg. output of a 3d plot function. # # OUTPUT: # A string that represents the surface in the STL format. # # COMMENTS: # (1) You must view the surface before plotting it. # Otherwise, this will not work. # (2) In order to do 3d printing with this, you will need to # convert it into gcode. Skeinforge is an open-source # program that can do this. # (3) The size of the surface is not normalized in export. # Sage's units will become the units of the STL # description. These seem to be ~0.05 cm (at least when # printed using skeinforge -> replicatorg -> hacklab.to's # cupcake). # (4) Be aware of the overhang limits of your 3d printer; # most printers can only handle an overhang of Pi/2 (45*) # before your model will start drooping. # # EXAMPLES: # sage: x,y,z = var('x,y,z') # sage: a = implicit_plot3d(x^2+y^2+z^2-9, [x,-5,5], [y,-5,5],[z, # -5,5]) # sage: surface_to_stl_filesave(a,'file') # stl=open(filename + ".stl",'w'); stl.write('solid mathsurface\n'); for i in surface.face_list(): n = ( i[1][1]*i[2][2] - i[2][1]*i[1][2], i[1][2]*i[2][0] - i[1][0]*i[2][2], i[1][0]*i[2][1] - i[2][0]*i[1][1] ) abs = (n[0]^2+n[1]^2+n[2]^2)^0.5 n= (n[0]/abs,n[1]/abs,n[2]/abs) stl.write(' facet normal ' + repr(n[0]) + ' ' + repr(n[1]) + ' ' + repr(n[2]) + '\n'); stl.write(' outer loop\n'); stl.write(' vertex ' + repr(i[0][0]) + ' ' + repr(i[0][1]) + ' ' + repr(i[0][2]) + '\n'); stl.write(' vertex ' + repr(i[1][0]) + ' ' + repr(i[1][1]) + ' ' + repr(i[1][2]) + '\n'); stl.write(' vertex ' + repr(i[2][0]) + ' ' + repr(i[2][1]) + ' ' + repr(i[2][2]) + '\n'); stl.write(' endloop\n'); stl.write(' endfacet\n'); stl.write('endsolid surface\n'); stl.close(); return # Functions for Curve Followers # Translation Distances - evaluates the parametric function at t = s to determine the translation distance. def trans_point(r,s): return f[r](t=s) # Rotation Angles - takes the tangent line at time t = v and projects it onto the xy, yz, and xz planes when u = 0, 1, or 2 respectively. Then it finds the angle between the projection and the respective x, y and z unit vectors using arctangent of the slope. def angle(u,v): if diff(f[u])(t = v) == 0: return pi/2 else: return arctan(diff(f[(u+1)%3])(t = v)/diff(f[u])(t = v)) # Sphere Curve Follower - f is a parametric function for a curve such that f = [x(t),y(t),z(t)], n is the number of shapes desired on the curve, (a,b) is the interval for t, and radius is the radius of each sphere. def curve_fol_sphere(f,n,(a,b),radius): step = (b - a)/n x0 = trans_point(0,a) y0 = trans_point(1,a) z0 = trans_point(2,a) combo = TransZ(TransY(TransX(Sphere(radius),x0),y0),z0) for i in range(1,n): tnew = a + i*step x1 = trans_point(0,tnew) y1 = trans_point(1,tnew) z1 = trans_point(2,tnew) next_sphere = TransZ(TransY(TransX(Sphere(radius),x1),y1),z1) combo = Union(combo, next_sphere) return combo # Cylinder Curve Follower - f is a parametric function for a curve such that f = [x(t),y(t),z(t)], n is the number of shapes desired on the curve, (a,b) is the interval for t, and """""size is the size of each cube.""""""" def curve_fol_cyyl(f,n,(a,b),(c,d,e)): step = (b - a)/n x0 = trans_point(0,a) y0 = trans_point(1,a) z0 = trans_point(2,a) angxy0 = angle(0,a) angyz0 = angle(1,a)+pi/2 angxz0 = angle(2,a) cyll = RotateRZ(RotateRY(RotateRX(Cyyl(c,d,e),angxy0),angyz0),angxz0) combo = TransZ(TransY(TransX(cyll,x0),y0),z0) for i in range(1,n): tnew = a + i*step x1 = trans_point(0,tnew) y1 = trans_point(1,tnew) z1 = trans_point(2,tnew) angxy1 = angle(0,tnew) angyz1 = angle(1,tnew)+pi/2 angxz1 = angle(2,tnew) next_cyyl = RotateRZ(RotateRY(RotateRX(Cyyl(c,d,e),angxy1),angyz1),angxz1) move_next_cyyl = TransZ(TransY(TransX(next_cyyl,x1),y1),z1) combo = Union(combo, move_next_cyyl) return combo # Box Curve Follower - f is a parametric function for a curve such that f = [x(t),y(t),z(t)], n is the number of shapes desired on the curve, (a,b) is the interval for t, and size is the size of each cube. def curve_fol_box(f,n,(a,b),size): step = (b - a)/n x0 = trans_point(0,a) y0 = trans_point(1,a) z0 = trans_point(2,a) angxy0 = angle(0,a) angyz0 = angle(1,a) angxz0 = angle(2,a) box = RotateRZ(RotateRY(RotateRX(Cube(size),angxy0),angyz0),angxz0) combo = TransZ(TransY(TransX(box,x0),y0),z0) for i in range(1,n): tnew = a + i*step x1 = trans_point(0,tnew) y1 = trans_point(1,tnew) z1 = trans_point(2,tnew) angxy1 = angle(0,tnew) angyz1 = angle(1,tnew) angxz1 = angle(2,tnew) next_box = RotateRZ(RotateRY(RotateRX(Cube(size),angxy1),angyz1),angxz1) move_next_box = TransZ(TransY(TransX(next_box,x1),y1),z1) combo = Union(combo,move_next_box) return combo /// }}} {{{id=92| # "Drope Block" a sphere with the drope function on 4 of its 6 "sides" - Adapted from Nicholas Lewis sp = Sphere(4) dr = TransZ(Drope (4),2.5) top = dr side1 = RotateY(top,90) ts1 = Intersect(top ,side1) bs2 = RotateY(ts1,180) tube =Intersect(ts1 ,bs2) sld = Intersect(tube,sp) dbplt = Plot3d(sld,5,100) dbplt /// }}} {{{id=94| # "Sinus Bugs" two interlocking bugs patterned with a sinus - Adapted from Nicholas Lewis t1 = 5*Bug (-.5,1, 4) t2 = 5*Bug (.5,1, 4) s = Sinus (0,5) sld = Combine(Union(t1,t2),s,1) plt = Plot3d(sld,6,200) plt /// }}} {{{id=93| # "Super Wiffle" a ball locked inside a tetrahedron c = Tetrahedral (18,18,60) sp = Sphere(1.5) sld = Union(c,sp) swplt = Plot3d(sld,10,100) swplt /// }}} {{{id=95| # "Sinus Sphere" a sphere patterned with a sinus - Adapted from Nicholas Lewis a = Sinus(0,4) b = (cos(x) * cos(y)) * 10 c = Sphere(4) sld = Intersect(b-a+2,c) Splt = Plot3d(sld,4,100) Splt /// }}} {{{id=96| #Heart hearts=Plot3d(Heart(1,9/4,1,1,9/80),1.5,100) hearts /// }}} {{{id=86| # "Spaceship" a spaceship modeled using prisms, a cone, a cylinder and the sinus sphere q=TransZ(TransX(RotateRY(Prism(1,.25,3),-pi/9),.75),8) r=Union(q,RotateRZ(q,pi)) r2=Union(r,RotateRZ(r,pi/2)) spaceship=implicit_plot3d(Union(r2,Union(TransZ(RotateRX(ScaleXYZ(sld,.25),pi),10),Union(TransZ(Cyyl(.35,.35,6),7),Cone(1,1,9)))),(x, -5, 5), (y, -5, 5), (z, -.25, 12), plot_points=100) spaceship /// }}} {{{id=103| # "Sphere Circle" t = var('t') f = [4*sin(t), 4*cos(t), 0*t] circ=curve_fol_sphere(f,7,(0,2*pi),2) Plot3d(circ,10,100) /// }}} {{{id=105| # "Stacked Sphere Circle" t = var('t') f = [4*sin(t), 4*cos(t), 2*t/t] circ2=curve_fol_sphere(f,7,(0,2*pi),2) criclplt=Plot3d(Union(circ,circ2),10,100) criclplt /// }}} {{{id=110| #stl_outputs surface_to_stl_filesave(spaceship,'spaceship') surface_to_stl_filesave(criclplt,'criclplt') surface_to_stl_filesave(hearts,'hearts') surface_to_stl_filesave(Splt,'Splt') surface_to_stl_filesave(swplt,'swplt') surface_to_stl_filesave(plt,'plt') surface_to_stl_filesave(dbplt,'dbplt') /// }}} {{{id=111| %auto # Interactive Curve Follower: Various parameters controlling the creation of a parametric curve on which 3D object will be placed are presented. Once the proper parameters have been selected a 3d model of the figure is displayed. var('t x y z') inter_plot = 0 @interact def curve_fol(shape_type = ("Shape",['Sphere','Cube','Cylinder']), rotshapes = checkbox(True, "Rotate Shapes to Match Curve?"), n = ("# of Shapes on Curve",1), xfun = ("x(t)", t), yfun = ("y(t)", t), zfun = ("z(t)", t), a = ("t start", 0), b = ("t end",1), radius = ("radius", 1), height = ("height", 1), showplot = checkbox(True, "Display Shape?"), xaxes = ("X-axis Size", 10), yaxes = ("Y-axis Size", 10), zaxes = ("Z-axis Size", 10), saveplot = checkbox(False, "Save Plot?"), auto_update = False): var('t x y z') g = (xfun,yfun,zfun) if shape_type == 'Cylinder': shape_fun = Cyyl if shape_type == 'Sphere': shape_fun = Sphere if shape_type == 'Cube': shape_fun = Cube def trans_point2(r,s): return g[r](t=s) def angle(u,v): if diff(g[u])(t = v) == 0: return pi/2 else: return arctan(diff(g[(u+1)%3])(t = v)/diff(g[u])(t = v)) if shape_type == 'Cylinder': step = (b - a)/n x0 = trans_point2(0,a) y0 = trans_point2(1,a) z0 = trans_point2(2,a) angxy0 = angle(0,a) angyz0 = angle(1,a)+pi/2 angxz0 = angle(2,a) if rotshapes: shape1 = RotateRZ(RotateRY(RotateRX(Cyyl(radius,radius,height),angxy0),angyz0),angxz0) else: shape1 = Cyyl(radius,radius,height) combo = TransZ(TransY(TransX(shape1,x0),y0),z0) for i in range(1,n): tnew = a + i*step x1 = trans_point2(0,tnew) y1 = trans_point2(1,tnew) z1 = trans_point2(2,tnew) angxy1 = angle(0,tnew) angyz1 = angle(1,tnew)+pi/2 angxz1 = angle(2,tnew) if rotshapes: shape_next = RotateRZ(RotateRY(RotateRX(Cyyl(radius,radius,height),angxy0),angyz0),angxz0) else: shape_next = Cyyl(radius,radius,height) next_sphere = TransZ(TransY(TransX(shape_next,x1),y1),z1) combo = Union(combo, next_sphere) elif shape_type == 'Cube': step = (b - a)/n x0 = trans_point2(0,a) y0 = trans_point2(1,a) z0 = trans_point2(2,a) angxy0 = angle(0,a) angyz0 = angle(1,a) angxz0 = angle(2,a) if rotshapes: shape1 = RotateRZ(RotateRY(RotateRX(Cube(radius),angxy0),angyz0),angxz0) else: shape1 = Cube(radius) combo = TransZ(TransY(TransX(shape1,x0),y0),z0) for i in range(1,n): tnew = a + i*step x1 = trans_point2(0,tnew) y1 = trans_point2(1,tnew) z1 = trans_point2(2,tnew) angxy1 = angle(0,tnew) angyz1 = angle(1,tnew) angxz1 = angle(2,tnew) if rotshapes: shape_next = RotateRZ(RotateRY(RotateRX(Cube(radius),angxy0),angyz0),angxz0) else: shape_next = Cube(radius) next_sphere = TransZ(TransY(TransX(shape_next,x1),y1),z1) combo = Union(combo, next_sphere) else: step = (b - a)/n x0 = trans_point2(0,a) y0 = trans_point2(1,a) z0 = trans_point2(2,a) combo = TransZ(TransY(TransX(Sphere(radius),x0),y0),z0) for i in range(1,n): tnew = a + i*step x1 = trans_point2(0,tnew) y1 = trans_point2(1,tnew) z1 = trans_point2(2,tnew) next_sphere = TransZ(TransY(TransX(Sphere(radius),x1),y1),z1) combo = Union(combo, next_sphere) inter_plot = implicit_plot3d(combo,(x,-xaxes,xaxes),(y,-yaxes,yaxes),(z,-zaxes,zaxes)) if showplot: show(inter_plot) if saveplot: surface_to_stl_filesave(inter_plot,'inter_plot') return inter_plot /// }}} {{{id=114| var('t') f = [t,t*t,t] v = curve_fol_cyyl(f,3,(0,1),(1,1,1)) Plot3d(v,6,100) /// }}}