1 # Stairbuilder - Stringer generation
3 # Generates stringer mesh for stair generation.
5 # - id1 = Freestanding staircase
6 # - id2 = Housed-open staircase
7 # - id3 = Box staircase
8 # - id4 = Circular staircase
9 # Stringer Type (typ_s):
14 # Paul "BrikBot" Marshall
15 # Created: September 19, 2011
16 # Last Modified: February 16, 2011
17 # Homepage (blog): http://post.darkarsenic.com/
18 # //blog.darkarsenic.com/
20 # Coded in IDLE, tested in Blender 2.62.
21 # Search for "@todo" to quickly find sections that need work.
23 # ##### BEGIN GPL LICENSE BLOCK #####
25 # Stairbuilder is for quick stair generation.
26 # Copyright (C) 2011 Paul Marshall
28 # This program is free software: you can redistribute it and/or modify
29 # it under the terms of the GNU General Public License as published by
30 # the Free Software Foundation, either version 3 of the License, or
31 # (at your option) any later version.
33 # This program is distributed in the hope that it will be useful,
34 # but WITHOUT ANY WARRANTY; without even the implied warranty of
35 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
36 # GNU General Public License for more details.
38 # You should have received a copy of the GNU General Public License
39 # along with this program. If not, see <http://www.gnu.org/licenses/>.
41 # ##### END GPL LICENSE BLOCK #####
43 from math import atan, cos, radians, tan
44 from mathutils import Matrix, Vector
45 from mathutils.geometry import (intersect_line_plane,
49 def __init__(self,G,typ,typ_s,rise,run,w,h,nT,hT,wT,tT,tO,tw,tf,tp,g,
50 nS=1,dis=False,notMulti=True,deg=4):
52 self.typ = typ # Stair type
53 self.typ_s = typ_s # Stringer type
54 self.rise = rise #Stair rise
55 self.run = run #Stair run. Degrees if self.typ == "id4"
57 self.w = w / 100 #stringer width
59 self.w = (wT * (w / 100)) / nS
60 self.h = h #stringer height
61 self.nT = nT #number of treads
62 self.hT = hT #tread height
63 self.wT = wT #tread width
64 self.tT = tT #tread toe
65 self.tO = tO #Tread overhang. Inner radius if self.typ == "id4"
66 self.tw = self.w * (tw / 100) #stringer web thickness
67 self.tf = tf #stringer flange thickness
68 self.tp = 1 - (tp / 100) #stringer flange taper
69 self.g = g #does stringer intersect the ground?
70 self.nS = nS #number of stringers
71 self.dis = dis #Use distributed stringers
72 self.deg = deg #number of sections per "slice". Only applys if self.typ == "id4"
73 # Default stringer object (classic / sId1):
74 self.faces1=[[0,1,3,2],[1,5,3],[3,5,4],[6,7,9,8],[7,11,9],[9,11,10],
75 [0,2,8,6],[0,1,7,6],[1,5,11,7],[2,3,9,8],[3,4,10,9],[4,5,11,10]]
76 # Box stair type stringer:
77 self.faces2=[[0,1,7,6],[1,3,9,7],[3,4,10,9],[4,10,11,5],[5,11,8,2],
78 [2,8,6,0],[0,1,2],[1,2,5,3],[3,4,5],[6,7,8],[7,8,11,9],[9,10,11]]
79 # I-beam stringer (id2 / sId2 / Taper < 100%):
80 self.faces3a=[[0,1,17,16],[1,2,18,17],[2,3,19,18],[3,4,20,19],[4,5,21,20],[5,6,22,21],
81 [6,7,23,22],[7,8,24,23],[8,9,25,24],[9,10,26,25],[10,11,27,26],
82 [11,12,28,27],[12,13,29,28],[13,14,30,29],[14,15,31,30],[15,0,16,31],
83 [0,1,2,15],[2,11,14,15],[11,12,13,14],[2,3,10,11],[3,4,5,6],[3,6,7,10],
84 [7,8,9,10],[16,17,18,31],[18,27,30,31],[27,28,29,30],[18,19,26,27],
85 [19,20,21,22],[19,22,23,26],[23,24,25,26]]
86 # I-beam stringer (id2 / sId2 / Taper = 100%):
87 self.faces3b=[[0,1,9,8],[1,2,10,9],[2,3,11,10],[3,4,12,11],[4,5,13,12],[5,6,14,13],
88 [6,7,15,14],[7,0,8,15],[0,1,6,7],[1,2,5,6],[2,3,4,5],[8,9,14,15],
89 [9,10,13,14],[10,11,12,13]]
90 # I-beam stringer (id3 / sId2 / Taper < 100%):
91 self.faces3c=[[0,1,2,7],[2,3,6,7],[3,4,5,6],[1,2,23,16],[2,3,22,23],
92 [3,4,21,22],[16,17,18,23],[18,19,22,23],[19,20,21,22],
93 [17,8,15,18],[18,15,14,19],[19,14,13,20],[8,9,10,15],
94 [10,11,14,15],[11,12,13,14],[9,10,53,52],[10,11,54,53],
95 [11,12,55,54],[52,53,61,60],[53,54,62,61],[54,55,63,62],
96 [60,61,34,33],[61,62,35,34],[62,63,36,35],[32,33,34,39],
97 [34,35,38,39],[35,36,37,38],[41,32,39,42],[42,39,38,43],
98 [43,38,37,44],[40,41,42,47],[42,43,46,47],[43,44,45,46],
99 [25,26,47,40],[26,27,46,47],[27,28,45,46],[24,25,26,31],
100 [26,27,30,31],[27,28,29,30],[24,31,57,56],[31,30,58,57],
101 [30,29,59,58],[48,49,57,56],[49,50,58,57],[50,51,59,58],
102 [0,7,49,48],[7,6,50,49],[6,5,51,50],[0,1,16,48],[16,40,56,48],
103 [24,25,40,56],[16,17,41,40],[8,9,52,17],[17,52,60,41],
104 [32,33,60,41],[12,13,20,55],[20,44,63,55],[37,44,63,36],
105 [20,21,45,44],[28,29,51,21],[21,51,59,45],[28,45,59,29],
107 # C-beam stringer (id3 / sId3 / Taper < 100%):
108 self.faces4c=[[0,1,2,7],[2,3,6,7],[3,4,5,6],[1,2,23,16],[2,3,22,23],[3,4,21,22],
109 [16,17,18,23],[18,19,22,23],[19,20,21,22],[17,8,15,18],[18,15,14,19],
110 [19,14,13,20],[8,9,10,15],[10,11,14,15],[11,12,13,14],[0,24,25,7],
111 [7,25,26,6],[6,26,27,5],[9,31,30,10],[10,30,29,11],[11,29,28,12],
112 [24,25,30,31],[25,26,29,30],[26,27,28,29],[0,1,16,24],[16,24,31,17],
113 [8,9,31,17],[4,5,27,21],[20,21,27,28],[12,13,20,28]]
118 if self.typ == "id1":
119 if self.typ_s == "sId1":
120 if self.dis or self.nS == 1:
121 offset = (self.wT / (self.nS + 1)) - (self.w / 2)
124 for i in range(self.nS):
125 for j in range(self.nT):
127 coords.append(Vector([0, offset, -self.rise]))
128 coords.append(Vector([self.run, offset, -self.rise]))
129 coords.append(Vector([0, offset, -self.hT]))
130 coords.append(Vector([self.run, offset, -self.hT]))
131 coords.append(Vector([self.run, offset, 0]))
132 coords.append(Vector([self.run * 2, offset, 0]))
134 coords.append(coords[k]+Vector([0, self.w, 0]))
136 k += j*Vector([self.run, 0, self.rise])
137 self.G.Make_mesh(coords,self.faces1,'stringer')
138 if self.dis or self.nS == 1:
139 offset += self.wT / (self.nS + 1)
141 offset += (self.wT - self.w) / (self.nS - 1)
142 elif self.typ_s == "sId2":
144 elif self.typ == "id2":
145 if self.typ_s == "sId1":
147 coords.append(Vector([-self.tT, -self.w, -self.rise]))
148 coords.append(Vector([self.hT / self.G.slope, -self.w, -self.rise]))
149 coords.append(Vector([-self.tT, -self.w, 0]))
150 coords.append(Vector([self.nT * self.run, -self.w,
151 ((self.nT - 1) * self.rise) - self.hT]))
152 coords.append(Vector([self.nT * self.run, -self.w, self.nT * self.rise]))
153 coords.append(Vector([(self.nT * self.run) - self.tT, -self.w,
154 self.nT * self.rise]))
156 coords.append(coords[i] + Vector([0, self.w, 0]))
157 self.G.Make_mesh(coords, self.faces2, 'stringer')
159 i += Vector([0, self.w + self.wT, 0])
160 self.G.Make_mesh(coords, self.faces2, 'stringer')
161 elif self.typ_s == "sId2":
163 elif self.typ_s == "sId3":
165 elif self.typ == "id3":
166 h = (self.rise - self.hT) - self.rise #height of top section
167 for i in range(self.nT):
169 coords.append(Vector([i * self.run,0,-self.rise]))
170 coords.append(Vector([(i + 1) * self.run,0,-self.rise]))
171 coords.append(Vector([i * self.run,0,h + (i * self.rise)]))
172 coords.append(Vector([(i + 1) * self.run,0,h + (i * self.rise)]))
174 coords.append(coords[j] + Vector([0,self.wT,0]))
175 self.G.Make_mesh(coords, self.G.faces, 'stringer')
176 elif self.typ == "id4":
177 if self.typ_s == "sId1":
178 # Center of the strigner:
179 offset = (self.wT / (self.nS + 1))
180 for s in range(self.nS):
181 # Base location for the stringer:
182 base = self.tO + (offset * (s + 1)) - (self.w / 2)
183 start = [Vector([0, -base, -self.hT]),
184 Vector([0, -base, -self.hT - self.rise]),
185 Vector([0, -base - self.w, -self.hT]),
186 Vector([0, -base - self.w, -self.hT - self.rise])]
187 self.d = radians(self.run) / self.nT
188 for i in range(self.nT):
190 # Base faces. Should be able to append more sections:
191 tId4_faces = [[0, 1, 3, 2]]
192 # Generate inner coordinates:
193 t_inner = Matrix.Rotation(self.d * i, 3, 'Z')
194 coords.append((t_inner * start[0]) + Vector([0, 0, self.rise * i]))
195 coords.append((t_inner * start[1]) + Vector([0, 0, self.rise * i]))
196 # Generate outer coordinates:
197 t_outer = Matrix.Rotation(self.d * i, 3, 'Z')
198 coords.append((t_outer * start[2]) + Vector([0, 0, self.rise * i]))
199 coords.append((t_outer * start[3]) + Vector([0, 0, self.rise * i]))
200 # Vert tracking variable:
202 for j in range(self.deg):
204 tId4_faces.append([k, k - 4, k - 3, k + 1])
205 tId4_faces.append([k - 2, k - 1, k + 3, k + 2])
206 tId4_faces.append([k + 1, k - 3, k - 1, k + 3])
207 tId4_faces.append([k, k - 4, k - 2, k + 2])
208 rot = Matrix.Rotation(((self.d * (j + 1)) / self.deg) + (self.d * i), 3, 'Z')
210 coords.append((rot * v) + Vector([0, 0, self.rise * i]))
211 for j in range(self.deg):
212 k = ((j + self.deg) * 4) + 4
213 tId4_faces.append([k, k - 4, k - 3, k + 1])
214 tId4_faces.append([k - 2, k - 1, k + 3, k + 2])
215 tId4_faces.append([k + 1, k - 3, k - 1, k + 3])
216 tId4_faces.append([k, k - 4, k - 2, k + 2])
217 rot = Matrix.Rotation(((self.d * ((j + self.deg) + 1)) / self.deg) + (self.d * i), 3, 'Z')
220 incline = (self.rise * i) + (self.rise / self.deg) * (j + 1)
221 coords.append((rot * start[v]) + Vector([0, 0, incline]))
223 coords.append((rot * start[v]) + Vector([0, 0, self.rise * i]))
224 self.G.Make_mesh(coords, tId4_faces, 'treads')
225 elif self.typ_s == "sId2":
226 self.circular_I_Beam()
231 # Adds a scalar to the given list.
232 # Util method to implement addition for use in generating the circular
233 # stringer. Uses recursion to deal with multi-dimensional lists.
234 def add(self, scalar, matrix):
235 if matrix.__class__.__name__ == 'list':
236 for i in range(len(matrix)):
237 matrix[i] = self.add(scalar, matrix[i])
238 elif matrix.__class__.__name__ in ('int', 'float'):
239 matrix = matrix + scalar
246 # Bottom of the stringer:
247 baseZ = -self.rise - self.hT - self.h
248 # Top of the strigner:
249 topZ = -self.rise - self.hT
250 # Vertical taper amount:
251 taper = self.tf * self.tp
253 if self.dis or self.nS == 1:
254 offset = (self.wT / (self.nS + 1)) - mid
260 for i in range(self.nS):
262 coords.append(Vector([0, offset, baseZ]))
263 coords.append(Vector([0, offset, baseZ + taper]))
264 coords.append(Vector([0, offset + (mid - web), baseZ + self.tf]))
265 coords.append(Vector([0, offset + (mid - web), topZ - self.tf]))
266 coords.append(Vector([0, offset, topZ - taper]))
267 coords.append(Vector([0, offset, topZ]))
268 coords.append(Vector([0, offset + (mid - web), topZ]))
269 coords.append(Vector([0, offset + (mid + web), topZ]))
270 coords.append(Vector([0, offset + self.w, topZ]))
271 coords.append(Vector([0, offset + self.w, topZ - taper]))
272 coords.append(Vector([0, offset + (mid + web), topZ - self.tf]))
273 coords.append(Vector([0, offset + (mid + web), baseZ + self.tf]))
274 coords.append(Vector([0, offset + self.w, baseZ + taper]))
275 coords.append(Vector([0, offset + self.w, baseZ]))
276 coords.append(Vector([0, offset + (mid + web), baseZ]))
277 coords.append(Vector([0, offset + (mid - web), baseZ]))
279 coords.append(coords[j]+Vector([self.run * self.nT, 0, self.rise * self.nT]))
280 # If the bottom meets the ground:
281 # Bottom be flat with the xy plane, but shifted down.
282 # Either project onto the plane along a vector (hard) or use the built in
283 # interest found in mathutils.geometry (easy). Using intersect:
286 coords[j] = intersect_line_plane(coords[j], coords[j + 16],
287 Vector([0, 0, topZ]),
289 self.G.Make_mesh(coords, self.faces3a, 'stringer')
291 if self.dis or self.nS == 1:
292 offset += self.wT / (self.nS + 1)
294 offset += (self.wT - self.w) / (self.nS - 1)
297 for i in range(self.nS):
299 coords.append(Vector([0, offset, baseZ]))
300 coords.append(Vector([0, offset + (mid - web), baseZ + self.tf]))
301 coords.append(Vector([0, offset + (mid - web), topZ - self.tf]))
302 coords.append(Vector([0, offset, topZ]))
303 coords.append(Vector([0, offset + self.w, topZ]))
304 coords.append(Vector([0, offset + (mid + web), topZ - self.tf]))
305 coords.append(Vector([0, offset + (mid + web), baseZ + self.tf]))
306 coords.append(Vector([0, offset + self.w, baseZ]))
308 coords.append(coords[j]+Vector([self.run * self.nT, 0, self.rise * self.nT]))
309 self.G.Make_mesh(coords, self.faces3b, 'stringer')
310 offset += self.wT / (self.nS + 1)
315 def housed_I_beam(self):
316 webOrth = Vector([self.rise, 0, -self.run]).normalized()
317 webHeight = Vector([self.run + self.tT, 0, -self.hT]).project(webOrth).length
318 vDelta_1 = self.tf * tan(self.G.angle)
319 vDelta_2 = (self.rise * (self.nT - 1)) - (webHeight + self.tf)
320 flange_y = (self.w - self.tw) / 2
321 front = -self.tT - self.tf
322 outer = -self.tO - self.tw - flange_y
326 # Upper-Outer flange:
327 coords.append(Vector([front, outer, -self.rise]))
328 coords.append(Vector([-self.tT, outer, -self.rise]))
329 coords.append(Vector([-self.tT, outer, 0]))
330 coords.append(Vector([(self.run * (self.nT - 1)) - self.tT, outer,
331 self.rise * (self.nT - 1)]))
332 coords.append(Vector([self.run * self.nT, outer,
333 self.rise * (self.nT - 1)]))
334 coords.append(Vector([self.run * self.nT, outer,
335 (self.rise * (self.nT - 1)) + self.tf]))
336 coords.append(Vector([(self.run * (self.nT - 1)) - self.tT, outer,
337 (self.rise * (self.nT - 1)) + self.tf]))
338 coords.append(Vector([front, outer, self.tf - vDelta_1]))
339 # Lower-Outer flange:
340 coords.append(coords[0] + Vector([self.tf + webHeight, 0, 0]))
341 coords.append(coords[1] + Vector([self.tf + webHeight, 0, 0]))
342 coords.append(intersect_line_line(coords[9],
343 coords[9] - Vector([0, 0, 1]),
344 Vector([self.run, 0, -self.hT - self.tf]),
345 Vector([self.run * 2, 0, self.rise - self.hT - self.tf]))[0])
346 coords.append(Vector([(self.run * self.nT) - ((webHeight - self.hT) / tan(self.G.angle)),
348 coords.append(coords[4] - Vector([0, 0, self.tf + webHeight]))
349 coords.append(coords[5] - Vector([0, 0, self.tf + webHeight]))
350 coords.append(coords[11] + Vector([0, 0, self.tf]))
351 coords.append(intersect_line_line(coords[8],
352 coords[8] - Vector([0, 0, 1]),
353 Vector([self.run, 0, -self.hT]),
354 Vector([self.run * 2, 0, self.rise - self.hT]))[0])
356 coords.append(coords[1] + Vector([0, flange_y, 0]))
357 coords.append(coords[8] + Vector([0, flange_y, 0]))
358 coords.append(coords[15] + Vector([0, flange_y, 0]))
359 coords.append(coords[14] + Vector([0, flange_y, 0]))
360 coords.append(coords[13] + Vector([0, flange_y, 0]))
361 coords.append(coords[4] + Vector([0, flange_y, 0]))
362 coords.append(coords[3] + Vector([0, flange_y, 0]))
363 coords.append(coords[2] + Vector([0, flange_y, 0]))
364 # Upper-Inner flange and lower-inner flange:
366 coords.append(coords[i] + Vector([0, self.w, 0]))
369 coords.append(coords[i + 16] + Vector([0, self.tw, 0]))
370 # Mid nodes to so faces will be quads:
371 for i in [0,7,6,5,9,10,11,12]:
372 coords.append(coords[i] + Vector([0, flange_y, 0]))
374 coords.append(coords[i + 48] + Vector([0, self.tw, 0]))
376 self.G.Make_mesh(coords, self.faces3c, 'stringer')
379 i += Vector([0, self.wT + self.tw, 0])
381 self.G.Make_mesh(coords, self.faces3c, 'stringer')
388 def circular_I_Beam(self):
389 # Mesh face definitions. Add "'slice #' * 16" to each for actual vert:
390 loop = [[0, 1, -15, -16], [1, 2, -14, -15], [2, 3, -13, -14], [3, 4, -12, -13],
391 [4, 5, -11, -12], [5, 6, -10, -11], [6, 7, -9, -10], [7, 8, -8, -9],
392 [8, 9, -7, -8], [9, 10, -6, -7], [10, 11, -5, -6], [11, 12, -4, -5],
393 [12, 13, -3, -4], [13, 14, -2, -3], [14, 15, -1, -2], [15, 0, -16, -1]]
394 end = [[0, 1, 14, 15], [1, 2, 5, 14], [2, 3, 4, 5], [5, 6, 13, 14],
395 [6, 7, 8, 9], [6, 9, 10, 13], [10, 11, 12, 13]]
396 # Center of stringer calculation:
397 offset = (self.wT / (self.nS + 1)) - (self.w / 2)
398 for s in range(self.nS):
399 base = -self.tO - (offset * (s + 1))
400 baseZ = -self.rise - self.hT
401 start = [Vector([0, base, baseZ]),
402 Vector([0, base - (self.w - self.tw) / 2, baseZ]),
403 Vector([0, base - (self.w - self.tw), baseZ]),
404 Vector([0, base - self.w, baseZ]),
405 Vector([0, base - self.w, baseZ - self.tp]),
406 Vector([0, base - (self.w - self.tw), baseZ - self.tf]),
407 Vector([0, base - (self.w - self.tw), baseZ - self.h + self.tf]),
408 Vector([0, base - self.w, baseZ - self.h + self.tp]),
409 Vector([0, base - self.w, baseZ - self.h]),
410 Vector([0, base - (self.w - self.tw), baseZ - self.h]),
411 Vector([0, base - (self.w - self.tw) / 2, baseZ - self.h]),
412 Vector([0, base, baseZ - self.h]),
413 Vector([0, base, baseZ - self.h + self.tp]),
414 Vector([0, base - (self.w - self.tw) / 2, baseZ - self.h + self.tf]),
415 Vector([0, base - (self.w - self.tw) / 2, baseZ - self.tf]),
416 Vector([0, base, baseZ - self.tp])]
422 self.d = radians(self.run) / self.nT
423 for i in range(self.nS):
426 # Base faces. Should be able to append more sections:
429 # Shift verts over and rotate:
430 rot = Matrix.Rotation(self.d * i, 3, 'Z')
431 for v in range(len(start)):
432 start[v][1] = start[v][1] + (offset * i)
433 coords.append((rot * start[v]) + Vector([0, 0, self.rise * i]))
436 for j in range(self.deg):
438 for l in self.add(k, loop):
440 rot = Matrix.Rotation(((self.d * (j + 1)) / self.deg) + (self.d * i), 3, 'Z')
442 coords.append((rot * v) + Vector([0, 0, self.rise * i]))
443 for f in self.add(k, end):
445 self.G.Make_mesh(coords, tId4_faces, 'stringer')
453 # Bottom of the stringer:
454 baseZ = -self.rise - self.hT - self.h
455 # Top of the strigner:
456 topZ = -self.rise - self.hT
457 # Vertical taper amount:
458 taper = self.tf * self.tp
460 if self.dis or self.nS == 1:
461 offset = (self.wT / (self.nS + 1)) - mid
467 for i in range(self.nS):
469 coords.append(Vector([0, offset, baseZ]))
470 coords.append(Vector([0, offset, baseZ + taper]))
471 coords.append(Vector([0, offset + (mid - web), baseZ + self.tf]))
472 coords.append(Vector([0, offset + (mid - web), topZ - self.tf]))
473 coords.append(Vector([0, offset, topZ - taper]))
474 coords.append(Vector([0, offset, topZ]))
475 coords.append(Vector([0, offset + (mid - web), topZ]))
476 coords.append(Vector([0, offset + (mid + web), topZ]))
477 coords.append(Vector([0, offset + self.w, topZ]))
478 coords.append(Vector([0, offset + self.w, topZ - taper]))
479 coords.append(Vector([0, offset + (mid + web), topZ - self.tf]))
480 coords.append(Vector([0, offset + (mid + web), baseZ + self.tf]))
481 coords.append(Vector([0, offset + self.w, baseZ + taper]))
482 coords.append(Vector([0, offset + self.w, baseZ]))
483 coords.append(Vector([0, offset + (mid + web), baseZ]))
484 coords.append(Vector([0, offset + (mid - web), baseZ]))
486 coords.append(coords[j]+Vector([self.run * self.nT, 0, self.rise * self.nT]))
487 # If the bottom meets the ground:
488 # Bottom be flat with the xy plane, but shifted down.
489 # Either project onto the plane along a vector (hard) or use the built in
490 # interest found in mathutils.geometry (easy). Using intersect:
493 coords[j] = intersect_line_plane(coords[j], coords[j + 16],
494 Vector([0, 0, topZ]),
496 self.G.Make_mesh(coords, self.faces3a, 'stringer')
498 if self.dis or self.nS == 1:
499 offset += self.wT / (self.nS + 1)
501 offset += (self.wT - self.w) / (self.nS - 1)
504 for i in range(self.nS):
506 coords.append(Vector([0, offset, baseZ]))
507 coords.append(Vector([0, offset + (mid - web), baseZ + self.tf]))
508 coords.append(Vector([0, offset + (mid - web), topZ - self.tf]))
509 coords.append(Vector([0, offset, topZ]))
510 coords.append(Vector([0, offset + self.w, topZ]))
511 coords.append(Vector([0, offset + (mid + web), topZ - self.tf]))
512 coords.append(Vector([0, offset + (mid + web), baseZ + self.tf]))
513 coords.append(Vector([0, offset + self.w, baseZ]))
515 coords.append(coords[j]+Vector([self.run * self.nT, 0, self.rise * self.nT]))
516 self.G.Make_mesh(coords, self.faces3b, 'stringer')
517 offset += self.wT / (self.nS + 1)
522 def housed_C_beam(self):
523 webOrth = Vector([self.rise, 0, -self.run]).normalized()
524 webHeight = Vector([self.run + self.tT, 0, -self.hT]).project(webOrth).length
525 vDelta_1 = self.tf * tan(self.G.angle)
526 vDelta_2 = (self.rise * (self.nT - 1)) - (webHeight + self.tf)
527 flange_y = (self.w - self.tw) / 2
528 front = -self.tT - self.tf
529 outer = -self.tO - self.tw - flange_y
533 # Upper-Outer flange:
534 coords.append(Vector([front, outer, -self.rise]))
535 coords.append(Vector([-self.tT, outer, -self.rise]))
536 coords.append(Vector([-self.tT, outer, 0]))
537 coords.append(Vector([(self.run * (self.nT - 1)) - self.tT, outer,
538 self.rise * (self.nT - 1)]))
539 coords.append(Vector([self.run * self.nT, outer,
540 self.rise * (self.nT - 1)]))
541 coords.append(Vector([self.run * self.nT, outer,
542 (self.rise * (self.nT - 1)) + self.tf]))
543 coords.append(Vector([(self.run * (self.nT - 1)) - self.tT, outer,
544 (self.rise * (self.nT - 1)) + self.tf]))
545 coords.append(Vector([front, outer, self.tf - vDelta_1]))
546 # Lower-Outer flange:
547 coords.append(coords[0] + Vector([self.tf + webHeight, 0, 0]))
548 coords.append(coords[1] + Vector([self.tf + webHeight, 0, 0]))
549 coords.append(intersect_line_line(coords[9],
550 coords[9] - Vector([0, 0, 1]),
551 Vector([self.run, 0, -self.hT - self.tf]),
552 Vector([self.run * 2, 0, self.rise - self.hT - self.tf]))[0])
553 coords.append(Vector([(self.run * self.nT) - ((webHeight - self.hT) / tan(self.G.angle)),
555 coords.append(coords[4] - Vector([0, 0, self.tf + webHeight]))
556 coords.append(coords[5] - Vector([0, 0, self.tf + webHeight]))
557 coords.append(coords[11] + Vector([0, 0, self.tf]))
558 coords.append(intersect_line_line(coords[8],
559 coords[8] - Vector([0, 0, 1]),
560 Vector([self.run, 0, -self.hT]),
561 Vector([self.run * 2, 0, self.rise - self.hT]))[0])
563 coords.append(coords[1] + Vector([0, flange_y, 0]))
564 coords.append(coords[8] + Vector([0, flange_y, 0]))
565 coords.append(coords[15] + Vector([0, flange_y, 0]))
566 coords.append(coords[14] + Vector([0, flange_y, 0]))
567 coords.append(coords[13] + Vector([0, flange_y, 0]))
568 coords.append(coords[4] + Vector([0, flange_y, 0]))
569 coords.append(coords[3] + Vector([0, flange_y, 0]))
570 coords.append(coords[2] + Vector([0, flange_y, 0]))
571 # Outer corner nodes:
572 for i in [0, 7, 6, 5, 12, 11, 10, 9]:
573 coords.append(coords[i] + Vector([0, flange_y + self.tw, 0]))
575 self.G.Make_mesh(coords, self.faces4c, 'stringer')
578 coords[i] += Vector([0, -outer * 2, 0])
580 coords[i + 16] += Vector([0, (-outer - flange_y) * 2, 0])
582 i += Vector([0, (self.tO * 2) + self.wT, 0])
584 self.G.Make_mesh(coords, self.faces4c, 'stringer')