1 # Stairbuilder - Tread generation
3 # Generates treads for stair generation.
5 # - id1 = Freestanding staircase
6 # - id2 = Housed-open staircase
7 # - id3 = Box staircase
8 # - id4 = Circular staircase
11 # - tId2 = Basic Steel
16 # Paul "BrikBot" Marshall
17 # Created: September 19, 2011
18 # Last Modified: January 26, 2012
19 # Homepage (blog): http://post.darkarsenic.com/
20 # //blog.darkarsenic.com/
22 # Coded in IDLE, tested in Blender 2.61.
23 # Search for "@todo" to quickly find sections that need work.
25 # ##### BEGIN GPL LICENSE BLOCK #####
27 # Stairbuilder is for quick stair generation.
28 # Copyright (C) 2011 Paul Marshall
30 # This program is free software: you can redistribute it and/or modify
31 # it under the terms of the GNU General Public License as published by
32 # the Free Software Foundation, either version 3 of the License, or
33 # (at your option) any later version.
35 # This program is distributed in the hope that it will be useful,
36 # but WITHOUT ANY WARRANTY; without even the implied warranty of
37 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
38 # GNU General Public License for more details.
40 # You should have received a copy of the GNU General Public License
41 # along with this program. If not, see <http://www.gnu.org/licenses/>.
43 # ##### END GPL LICENSE BLOCK #####
47 from math import radians, sqrt
48 from mathutils import Matrix, Vector
51 def __init__(self,G,typ,typ_t,run,w,h,d,r,toe,o,n,tk,sec,sp,sn,deg=4):
53 self.typ = typ #Stair type
54 self.typ_t = typ_t #Tread type
55 self.run = run #Stair run. Degrees if self.typ == "id4"
56 self.w=w #tread width. Is outer radius if self.typ == "id4"
57 self.h=h #tread height
58 self.d=d #tread run. Ignore for now if self.typ == "id4"
60 self.t=toe #tread nosing
61 self.o=o #tread side overhang. Is inner radius if self.typ == "id4"
62 self.n=n #number of treads
63 self.tk=tk #thickness of tread metal
64 self.sec=sec #metal sections for tread
65 if sec != 1 and typ_t not in ["tId4", "tId5"]:
66 self.sp=((d+toe)*(sp/100))/(sec-1) #spacing between sections (% of depth)
67 elif typ_t in ["tId4", "tId5"]:
68 self.sp=sp/100 #keep % value
71 self.sn=sn #number of cross sections
72 self.deg = deg #number of section per "slice". Only applys if self.typ == "id4"
73 self.tId2_faces = [[0,1,2,3],[0,3,4,5],[4,5,6,7],[6,7,8,9],[8,9,10,11],
74 [12,13,14,15],[12,15,16,17],[16,17,18,19],
75 [18,19,20,21],[20,21,22,23],[0,1,13,12],[1,2,14,13],
76 [2,3,15,14],[3,4,16,15],[4,7,19,16],[7,8,20,19],
77 [8,11,23,20],[11,10,22,23],[10,9,21,22],[9,6,18,21],
78 [6,5,17,18],[5,0,12,17]]
79 self.out_faces = [[0,2,3,1],[0,2,10,8],[9,11,3,1],[9,11,10,8],
80 [2,6,7,3],[2,6,14,10],[11,15,7,3],[11,15,14,10],
81 [0,4,5,1],[0,4,12,8],[9,13,5,1],[9,13,12,8],
82 [4,6,7,5],[4,6,14,12],[13,15,14,12],[13,15,7,5]]
86 # Setup the coordinates:
95 if self.typ in ["id1", "id2", "id3"]:
96 if self.typ_t == "tId1":
97 coords.append(Vector([-self.t,-self.o,0]))
98 coords.append(Vector([self.d,-self.o,0]))
99 coords.append(Vector([-self.t,self.w + self.o,0]))
100 coords.append(Vector([self.d,self.w + self.o,0]))
102 coords.append(coords[i]+Vector([0,0,-self.h]))
104 elif self.typ_t == "tId2":
105 depth = (self.d + self.t - (self.sec - 1) * self.sp) / self.sec
107 tDepth = depth - self.t
108 coords.append(Vector([-self.t, -self.o, -self.h])) #0
109 coords.append(Vector([inset - self.t, -self.o, -self.h])) #1
110 coords.append(Vector([inset - self.t, -self.o, -self.h + self.tk])) #2
111 coords.append(Vector([self.tk - self.t, -self.o, -self.h + self.tk])) #3
112 coords.append(Vector([self.tk - self.t, -self.o, -self.tk])) #4
113 coords.append(Vector([-self.t, -self.o, 0])) #5
114 coords.append(Vector([tDepth, -self.o, 0])) #6
115 coords.append(Vector([tDepth - self.tk, -self.o, -self.tk])) #7
116 coords.append(Vector([tDepth - self.tk, -self.o, self.tk - self.h])) #8
117 coords.append(Vector([tDepth, -self.o, -self.h])) #9
118 coords.append(Vector([tDepth - inset, -self.o, -self.h])) #10
119 coords.append(Vector([tDepth - inset, -self.o, -self.h + self.tk])) #11
121 coords.append(coords[i] + Vector([0, self.w + (2 * self.o), 0]))
123 elif self.typ_t in ["tId3", "tId4", "tId5"]:
125 coords.append(Vector([-self.t,-self.o,-self.h]))
126 coords.append(Vector([self.d,-self.o,-self.h]))
127 coords.append(Vector([-self.t,-self.o,0]))
128 coords.append(Vector([self.d,-self.o,0]))
131 coords.append(coords[i] + Vector([self.tk,self.tk,0]))
133 coords.append(coords[i] + Vector([-self.tk,self.tk,0]))
135 coords.append(coords[i] + Vector([0,self.w + self.o,0]))
137 coords.append(coords[i + 4] + Vector([0,self.w + self.o - (2 * self.tk),0]))
140 if self.typ_t == "tId3":
141 offset = (self.tk * sqrt(2)) / 2
142 topset = self.h - offset
143 self.sp = ((self.d + self.t - (2 * self.tk)) - (offset * (self.sec) + topset)) / (self.sec + 1)
144 baseX = -self.t + self.sp + self.tk
145 coords2.append(Vector([baseX, self.tk - self.o, offset - self.h]))
146 coords2.append(Vector([baseX + offset, self.tk - self.o, -self.h]))
148 coords2.append(coords2[i] + Vector([topset, 0, topset]))
150 coords2.append(coords2[i] + Vector([0, (self.w + self.o) - (2 * self.tk), 0]))
151 elif self.typ_t in ["tId4", "tId5"]:
152 offset = ((self.run + self.t) * self.sp) / (self.sec + 1)
153 topset = (((self.run + self.t) * (1 - self.sp)) - (2 * self.tk)) / self.sec
154 baseX = -self.t + self.tk + offset
155 baseY = self.w + self.o - 2 * self.tk
156 coords2.append(Vector([baseX, -self.o + self.tk, -self.h / 2]))
157 coords2.append(Vector([baseX + topset, -self.o + self.tk, -self.h / 2]))
158 coords2.append(Vector([baseX, -self.o + self.tk, 0]))
159 coords2.append(Vector([baseX + topset, -self.o + self.tk, 0]))
161 coords2.append(coords2[i] + Vector([0, baseY, 0]))
163 # Tread cross-sections:
164 if self.typ_t in ["tId3", "tId4"]:
166 cross = (self.w + (2 * self.o) - (self.sn + 2) * self.tk) / (self.sn + 1)
168 spacing = self.sp ** (1 / 4)
169 cross = ((2*self.o + self.w) * spacing) / (self.sn + 1)
170 cW = (-2*self.tk + (2*self.o + self.w) * (1 - spacing)) / self.sn
173 baseY = -self.o + self.tk + cross
174 coords3.append(Vector([-self.t + self.tk, baseY, -self.h]))
175 coords3.append(Vector([self.d - self.tk, baseY, -self.h]))
176 coords3.append(Vector([-self.t + self.tk, baseY, height]))
177 coords3.append(Vector([self.d - self.tk, baseY, height]))
179 coords3.append(coords3[i] + Vector([0, cW, 0]))
182 for i in range(self.n):
183 if self.typ_t == "tId1":
184 self.G.Make_mesh(coords,self.G.faces,'treads')
185 elif self.typ_t == "tId2":
189 for j in range(self.sec):
190 self.G.Make_mesh(temp, self.tId2_faces, 'treads')
192 k += Vector([depth + self.sp, 0, 0])
193 elif self.typ_t in ["tId3", "tId4", "tId5"]:
194 self.G.Make_mesh(coords,self.out_faces,'treads')
198 for j in range(self.sec):
199 self.G.Make_mesh(temp,self.G.faces,'bars')
201 k += Vector([offset + self.sp, 0, 0])
203 j += Vector([self.d, 0, self.r])
207 for j in range(self.sn):
208 self.G.Make_mesh(temp,self.G.faces,'crosses')
210 k += Vector([0, cW + cross, 0])
212 j += Vector([self.d, 0, self.r])
214 j += Vector([self.d,0,self.r])
215 # Circular staircase:
216 elif self.typ in ["id4"]:
217 start = [Vector([0, -self.o, 0]), Vector([0, -self.o, -self.h]),
218 Vector([0, -self.w, 0]), Vector([0, -self.w, -self.h])]
219 self.d = radians(self.run) / self.n
220 for i in range(self.n):
222 # Base faces. Should be able to append more sections:
223 tId4_faces = [[0, 1, 3, 2]]
224 t_inner = Matrix.Rotation((-self.t / self.o) + (self.d * i), 3, 'Z')
225 coords.append((t_inner * start[0]) + Vector([0, 0, self.r * i]))
226 coords.append((t_inner * start[1]) + Vector([0, 0, self.r * i]))
227 t_outer = Matrix.Rotation((-self.t / self.w) + (self.d * i), 3, 'Z')
228 coords.append((t_outer * start[2]) + Vector([0, 0, self.r * i]))
229 coords.append((t_outer * start[3]) + Vector([0, 0, self.r * i]))
231 for j in range(self.deg + 1):
233 tId4_faces.append([k, k - 4, k - 3, k + 1])
234 tId4_faces.append([k - 2, k - 1, k + 3, k + 2])
235 tId4_faces.append([k + 1, k - 3, k - 1, k + 3])
236 tId4_faces.append([k, k - 4, k - 2, k + 2])
237 rot = Matrix.Rotation(((self.d * j) / self.deg) + (self.d * i), 3, 'Z')
239 coords.append((rot * v) + Vector([0, 0, self.r * i]))
240 tId4_faces.append([k, k + 1, k + 3, k + 2])
241 self.G.Make_mesh(coords, tId4_faces, 'treads')