Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #! /usr/bin/env python
- '''
- Stairs and railing creator script for blender 2.49
- Author: Nick Trefiak
- Date: 2010 08 09
- Creates a straight-run staircase with railings and stringer
- All components are optional and can be turned on and off by setting e.g. makeTreads=True or makeTreads=False
- No GUI for the script, all parameters must be defined below
- Current values assume 1 blender unit = 1 metre
- Stringer will rest on lower landing and hang from upper landing
- Railings start on the lowest step and end on the upper landing
- NOTE: You must have numpy installed for this script to work!
- numpy is used to easily perform the necessary algebra
- numpy can be found at http://www.scipy.org/Download
- Note: I'm not sure how to use recalcNormals so not all normals points ouwards.
- Perhaps someone else can contribute this.
- '''
- #---------------------------------------------------------------------
- '''define all parameters here'''
- global rise, run
- rise=0.20 #single tread rise, including the tread height
- run=0.30 #single tread run, not including the nosing
- #for treads
- makeTreads=True
- wT=1.2 #tread width
- hT=0.04 #tread height
- tT=0.03 #tread toe, a.k.a. nosing
- nT=10 #number of treads
- #for posts
- makePosts=True
- dP=0.04 #post depth
- wP=0.04 #post width
- nP=5 #number of posts
- #for railings
- makeRailings=True
- wR=0.12 #rail width
- tR=0.03 #rail thickness
- hR=0.90 #rail height
- #for retainers
- makeRetainers=True
- wRR=0.01 #retainer width
- hRR=0.01 #retainer height
- nRR=3 #number of retainers
- #for stringer
- makeStringer=True
- wS=0.15 #stringer width, set equal to tread width for fully enclosed riser
- #---------------------------------------------------------------------
- '''import modules'''
- from Blender import *
- import bpy
- import math
- from numpy import *
- #---------------------------------------------------------------------
- '''classes for mesh creation'''
- class General:
- '''common data, methods needed for other objects'''
- def __init__(self,rise,run,N):
- self.start=zeros((3))
- self.stop=float(N)*array([run,0,rise])
- self.slope=rise/run
- self.angle=arctan(self.slope)
- #identical quads for all objects except stringer
- self.faces=[[0,1,3,2],[0,1,5,4],[0,2,6,4],[4,5,7,6],[2,3,7,6],[1,3,7,5]]
- def Make_mesh(self,coords,faces,meshname,objname):
- '''make a mesh given the vertex coordinates, faces, and names for mesh and object'''
- me = bpy.data.meshes.new(meshname)
- me.verts.extend(coords.tolist())
- me.faces.extend(faces)
- scn = bpy.data.scenes.active
- ob = scn.objects.new(me, objname)
- class Treads:
- '''class for creating treads'''
- def __init__(self,w,h,d,r,toe,N):
- self.w=w #tread width
- self.h=h #tread height
- self.d=d #tread run
- self.r=r #tread rise
- self.t=toe #tread nosing
- self.N=N #number of treads
- self.Create()
- def Create(self):
- for i in range(self.N):
- coords=zeros((8,3))
- coords[0,:]=[-self.t,0,0]
- coords[1,:]=[self.d,0,0]
- coords[2,:]=[-self.t,self.w,0]
- coords[3,:]=[self.d,self.w,0]
- coords[4:,:]=coords[0:4,:]+array([0,0,-self.h])
- coords=coords+array([i*self.d,0,i*self.r])
- G.Make_mesh(coords,G.faces,'tMesh','tObj')
- class Posts:
- '''class to create posts'''
- def __init__(self,d,w,wT,nP,hR,tR):
- self.x1=G.start+array([0,0,hR-tR]) #rail start
- self.x2=G.stop+array([0,0,hR-tR]) #rail stop
- self.d=d #post depth
- self.w=w #post width
- self.wT=wT #tread width
- self.nP=nP #number of posts
- self.sp=array([(self.x2[0]-self.x1[0])/float(nP+1),0,0]) #spacing between posts
- self.Create()
- def Intersect(self,i,d):
- '''find intersection point, x, for rail and post'''
- x3=self.x1+i*self.sp+d
- x4=x3+array([0,0,self.x2[-1]])
- a=self.x2-self.x1
- b=x4-x3
- c=x3-self.x1
- cr_ab=cross(a,b)
- mag_cr_ab=(cr_ab**2).sum()
- return self.x1+a*(dot(cross(c,b),cr_ab)/mag_cr_ab)
- def Create(self):
- for i in range(0,self.nP+2,1):
- coords=zeros((8,3))
- #intersections with rail
- coords[0]=self.Intersect(i,0.0)
- coords[1]=self.Intersect(i,self.d)
- #intersections with tread
- coords[2]=array([self.x1[0]+i*self.sp[0],0,int(coords[0,0]/run)*rise])
- coords[3]=coords[2]+array([self.d,0,0])
- #inner face
- coords[4:,:]=coords[0:4,:]+array([0,self.w,0])
- G.Make_mesh(coords,G.faces,'pMesh','pObj')
- #make post on other side of steps as well
- coords=coords+array([0,self.wT-self.w,0])
- G.Make_mesh(coords,G.faces,'pMesh','pObj')
- class Rails:
- '''class for creating railings'''
- def __init__(self,w,t,h,tT,wP,dP,wT):
- self.w=w #rail width
- self.t=t #rail thickness
- self.h=h #rail height
- self.start=G.start+array([0,0,self.h-self.t]) #rail start
- self.stop=G.stop+array([0,0,self.h-self.t]) #rail stop
- self.tT=tT #tread toe
- self.wP=wP #post width
- self.dP=dP #post depth
- self.wT=wT #tread width
- self.Create()
- def Create(self):
- #determine offset to include railing toe
- offset=array([self.tT,0,self.tT*tan(G.angle)])
- coords=zeros((8,3))
- coords[0]=self.start-offset
- coords[1]=self.stop+offset+array([self.dP,0,self.dP*tan(G.angle)])
- coords[2]=self.start-offset+array([0,self.w,0])
- coords[3]=self.stop+offset+array([self.dP,self.w,self.dP*tan(G.angle)])
- coords[4:,:]=coords[0:4,:]+array([0,0,self.t])
- #centre over posts
- coords=coords+array([0,0.5*(-self.w+self.wP),0])
- G.Make_mesh(coords,G.faces,'rMesh','rObj')
- #make rail on other side
- coords=coords+array([0,self.wT-self.wP,0])
- G.Make_mesh(coords,G.faces,'rMesh','rObj')
- class Retainers:
- '''class for creating retainers'''
- def __init__(self,w,h,wP,wT,nR):
- self.w=w #retainer width
- self.h=h #retainer height
- self.wP=wP #post width
- self.wT=wT #tread width
- self.nR=nR #number of retainers
- self.sp=hR/float(nR+1) #retainer spacing
- self.Create()
- def Create(self):
- for i in range(self.nR):
- coords=zeros((8,3))
- offset=(i+1)*array([0,0,self.sp])
- coords[0]=G.start+offset
- coords[1]=G.stop+offset
- coords[2]=G.start+offset+array([0,self.w,0])
- coords[3]=G.stop+offset+array([0,self.w,0])
- coords[4:,:]=coords[0:4,:]+array([0,0,self.h])
- #centre in posts
- coords=coords+array([0,0.5*(self.wP-self.w),0])
- G.Make_mesh(coords,G.faces,'rrMesh','rrObj')
- #make retainer on other side
- coords=coords+array([0,self.wT-self.wP,0])
- G.Make_mesh(coords,G.faces,'rrMesh','rrObj')
- class Stringer:
- '''class for creating stringer'''
- def __init__(self,w,nT,hT,wT):
- self.w=w #stringer width
- self.nT=nT #number of treads
- self.hT=hT #tread height
- self.wT=wT #tread width
- self.faces=[[0,1,3,2],[1,5,3],[3,5,4],[6,7,9,8],[7,11,9],[9,11,10],[0,2,8,6],[0,1,7,6],[1,5,11,7]]
- self.Create()
- def Create(self):
- for i in range(self.nT):
- coords=zeros((12,3))
- coords[0]=G.start+array([0,0,-rise])
- coords[1]=G.start+array([run,0,-rise])
- coords[2]=G.start+array([run*0,0,-self.hT])
- coords[3]=G.start+array([run*1,0,-self.hT])
- coords[4]=G.start+array([run*1,0,0])
- coords[5]=G.start+array([run*2,0,0])
- coords[6:]=coords[0:6]+array([0,self.w,0])
- coords=coords+i*array([run,0,rise])
- #centre below tread
- coords=coords+array([0,0.5*(self.wT-self.w),0])
- G.Make_mesh(coords,self.faces,'sMesh','sObj')
- #-----------------------------------------------------------
- '''create meshes'''
- editmode = Window.EditMode() # are we in edit mode? If so ...
- if editmode: Window.EditMode(0) # leave edit mode before getting the mesh
- global G
- G=General(rise,run,nT)
- if makeTreads: Treads(wT,hT,run,rise,tT,nT)
- if makePosts: Posts(dP,wP,wT,nP,hR,tR)
- if makeRailings: Rails(wR,tR,hR,tT,wP,dP,wT)
- if makeRetainers: Retainers(wRR,hRR,wP,wT,nRR)
- if makeStringer: Stringer(wS,nT,hT,wT)
- if editmode: Window.EditMode(1) # optional, just being nice
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement