From 080e472e77d24c6898e77e68081ed0c3cfc9265b Mon Sep 17 00:00:00 2001 From: Paul Marshall <portsidepaul@hotmail.com> Date: Thu, 29 Sep 2011 00:51:48 +0000 Subject: [PATCH] add_mesh_stairs New add-on in development for quick staircase generation. Currently feature incomplete. --- add_mesh_stairs/__init__.py | 67 +++++ add_mesh_stairs/general.py | 65 +++++ add_mesh_stairs/post.py | 87 ++++++ add_mesh_stairs/rail.py | 79 ++++++ add_mesh_stairs/retainer.py | 73 +++++ add_mesh_stairs/stairbuilder.py | 484 ++++++++++++++++++++++++++++++++ add_mesh_stairs/stringer.py | 291 +++++++++++++++++++ add_mesh_stairs/tread.py | 212 ++++++++++++++ 8 files changed, 1358 insertions(+) create mode 100644 add_mesh_stairs/__init__.py create mode 100644 add_mesh_stairs/general.py create mode 100644 add_mesh_stairs/post.py create mode 100644 add_mesh_stairs/rail.py create mode 100644 add_mesh_stairs/retainer.py create mode 100644 add_mesh_stairs/stairbuilder.py create mode 100644 add_mesh_stairs/stringer.py create mode 100644 add_mesh_stairs/tread.py diff --git a/add_mesh_stairs/__init__.py b/add_mesh_stairs/__init__.py new file mode 100644 index 00000000..31c1eddb --- /dev/null +++ b/add_mesh_stairs/__init__.py @@ -0,0 +1,67 @@ +# Paul "BrikBot" Marshall +# Created: July 24, 2011 +# Last Modified: Spetember 20, 2011 +# Homepage (blog): http://post.darkarsenic.com/ +# //blog.darkarsenic.com/ +# +# Coded in IDLE, tested in Blender 2.59. +# Search for "@todo" to quickly find sections that need work. +# +# ##### BEGIN GPL LICENSE BLOCK ##### +# +# The Blender Rock Creation tool is for rapid generation of mesh rocks in Blender. +# Copyright (C) 2011 Paul Marshall +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# ##### END GPL LICENSE BLOCK ##### + +bl_info = { + "name": "StairBuilder", + "author": "Nick van Adium", + "version": (1,1), + "blender": (2, 5, 9), + "api": 40249, + "location": "View3D > Add > Stairs", + "description": "Creates a straight-run staircase with railings and stringer", + "warning": "Add-on is very feature incomplete beyond basic functionality.", + "wiki_url": "", + "tracker_url": "", + "category": "Add Mesh"} + +if "bpy" in locals(): + import imp + imp.reload(stairbuilder) +else: + from add_mesh_stairs import stairbuilder + +import bpy + +# Register: + +def menu_func_stairs(self, context): + self.layout.operator(stairbuilder.stairs.bl_idname, text="StairBuilder", icon = "PLUGIN") + +def register(): + bpy.utils.register_module(__name__) + + bpy.types.INFO_MT_mesh_add.append(menu_func_stairs) + +def unregister(): + bpy.utils.unregister_module(__name__) + + bpy.types.INFO_MT_mesh_add.remove(menu_func_stairs) + +if __name__ == "__main__": + register() diff --git a/add_mesh_stairs/general.py b/add_mesh_stairs/general.py new file mode 100644 index 00000000..28a6be31 --- /dev/null +++ b/add_mesh_stairs/general.py @@ -0,0 +1,65 @@ +# Stairbuilder - General +# +# General is an object for creating meshes given the verts and faces. +# Stair Type (typ): +# - id1 = Freestanding staircase +# - id2 = Housed-open staircase +# - id3 = Box staircase +# - id4 = Circular staircase +# +# Paul "BrikBot" Marshall +# Created: September 19, 2011 +# Last Modified: September 20, 2011 +# Homepage (blog): http://post.darkarsenic.com/ +# //blog.darkarsenic.com/ +# +# Coded in IDLE, tested in Blender 2.59. +# Search for "@todo" to quickly find sections that need work. +# +# ##### BEGIN GPL LICENSE BLOCK ##### +# +# The Blender Rock Creation tool is for rapid generation of mesh rocks in Blender. +# Copyright (C) 2011 Paul Marshall +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# ##### END GPL LICENSE BLOCK ##### + +import bpy +from bpy_extras import object_utils +from math import atan +from mathutils import Vector + +class General: + def __init__(self,rise,run,N): + self.stop=float(N)*Vector([run,0,rise]) + self.slope=rise/run + self.angle=atan(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, verts, faces, name): + # Create new mesh + mesh = bpy.data.meshes.new(name) + + # Make a mesh from a list of verts/edges/faces. + mesh.from_pydata(verts, [], faces) + + # Set mesh to use auto smoothing: + mesh.use_auto_smooth = True + + # Update mesh geometry after adding stuff. + mesh.update() + + return object_utils.object_data_add(bpy.context, mesh, operator=None) diff --git a/add_mesh_stairs/post.py b/add_mesh_stairs/post.py new file mode 100644 index 00000000..c3f9218f --- /dev/null +++ b/add_mesh_stairs/post.py @@ -0,0 +1,87 @@ +# Stairbuilder - Post generation +# +# Generates posts for stair generation. +# Stair Type (typ): +# - id1 = Freestanding staircase +# - id2 = Housed-open staircase +# - id3 = Box staircase +# - id4 = Circular staircase +# +# Paul "BrikBot" Marshall +# Created: September 19, 2011 +# Last Modified: September 20, 2011 +# Homepage (blog): http://post.darkarsenic.com/ +# //blog.darkarsenic.com/ +# +# Coded in IDLE, tested in Blender 2.59. +# Search for "@todo" to quickly find sections that need work. +# +# ##### BEGIN GPL LICENSE BLOCK ##### +# +# The Blender Rock Creation tool is for rapid generation of mesh rocks in Blender. +# Copyright (C) 2011 Paul Marshall +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# ##### END GPL LICENSE BLOCK ##### + +from mathutils import Vector + +class Posts: + def __init__(self,G,rise,run,d,w,wT,nP,hR,tR, rEnable, lEnable): + self.G = G #General + self.rise = rise #Stair rise + self.run = run #Stair run + self.x1=Vector([0,0,hR-tR]) #rail start + self.x2=G.stop+Vector([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=Vector([(self.x2[0]-self.x1[0])/float(nP+1),0,0]) #spacing between posts + self.rEnable = rEnable + self.lEnable = lEnable + self.Create() + + def Intersect(self,i,d): + '''find intersection point, x, for rail and post''' + x3=self.x1+i*self.sp+Vector([d,d,d]) + x4=x3+Vector([0,0,self.x2[-1]]) + a=self.x2-self.x1 + b=x4-x3 + c=x3-self.x1 + cr_ab=a.cross(b) + mag_cr_ab=(cr_ab * cr_ab) + return self.x1+a*((c.cross(b).dot(cr_ab))/mag_cr_ab) + + def Create(self): + for i in range(0,self.nP+2,1): + coords = [] + #intersections with rail + coords.append(self.Intersect(i,0.0)) + coords.append(self.Intersect(i,self.d)) + #intersections with tread + coords.append(Vector([self.x1[0]+i*self.sp[0],0, + int(coords[0][0]/self.run)*self.rise])) + coords.append(coords[2]+Vector([self.d,0,0])) + #inner face + for j in range(4): + coords.append(coords[j]+Vector([0,self.w,0])) + if self.rEnable: + self.G.Make_mesh(coords, self.G.faces, 'posts') + if self.lEnable: + #make post on other side of steps as well + for j in coords: + j += Vector([0,self.wT-self.w,0]) + self.G.Make_mesh(coords, self.G.faces, 'posts') diff --git a/add_mesh_stairs/rail.py b/add_mesh_stairs/rail.py new file mode 100644 index 00000000..fd4949b2 --- /dev/null +++ b/add_mesh_stairs/rail.py @@ -0,0 +1,79 @@ +# Stairbuilder - Retainer generation +# +# Generates retainers for stair generation. +# Stair Type (typ): +# - id1 = Freestanding staircase +# - id2 = Housed-open staircase +# - id3 = Box staircase +# - id4 = Circular staircase +# +# Paul "BrikBot" Marshall +# Created: September 19, 2011 +# Last Modified: September 20, 2011 +# Homepage (blog): http://post.darkarsenic.com/ +# //blog.darkarsenic.com/ +# +# Coded in IDLE, tested in Blender 2.59. +# Search for "@todo" to quickly find sections that need work. +# +# ##### BEGIN GPL LICENSE BLOCK ##### +# +# The Blender Rock Creation tool is for rapid generation of mesh rocks in Blender. +# Copyright (C) 2011 Paul Marshall +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# ##### END GPL LICENSE BLOCK ##### + +from math import tan +from mathutils import Vector + +class Rails: + def __init__(self,G,w,t,h,tT,wP,dP,wT, rEnable, lEnable): + self.G = G #General + self.w=w #rail width + self.t=t #rail thickness + self.h=h #rail height + self.start=Vector([0,0,self.h-self.t]) #rail start + self.stop=G.stop+Vector([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.rEnable = rEnable + self.lEnable = lEnable + self.Create() + + def Create(self): + #determine offset to include railing toe + offset=Vector([self.tT,0,self.tT*tan(self.G.angle)]) + coords = [] + coords.append(self.start-offset) + coords.append(self.stop+offset+Vector([self.dP,0, + self.dP*tan(self.G.angle)])) + coords.append(self.start-offset+Vector([0,self.w,0])) + coords.append(self.stop+offset+Vector([self.dP,self.w, + self.dP*tan(self.G.angle)])) + for j in range(4): + coords.append(coords[j]+Vector([0,0,self.t])) + #centre over posts + for j in coords: + j += Vector([0,0.5*(-self.w+self.wP),0]) + if self.rEnable: + self.G.Make_mesh(coords, self.G.faces, 'rails') + if self.lEnable: + #make rail on other side + for j in coords: + j += Vector([0,self.wT-self.wP,0]) + self.G.Make_mesh(coords, self.G.faces, 'rails') diff --git a/add_mesh_stairs/retainer.py b/add_mesh_stairs/retainer.py new file mode 100644 index 00000000..dc0dd0e0 --- /dev/null +++ b/add_mesh_stairs/retainer.py @@ -0,0 +1,73 @@ +# Stairbuilder - Retainer generation +# +# Generates retainers for stair generation. +# Stair Type (typ): +# - id1 = Freestanding staircase +# - id2 = Housed-open staircase +# - id3 = Box staircase +# - id4 = Circular staircase +# +# Paul "BrikBot" Marshall +# Created: September 19, 2011 +# Last Modified: September 20, 2011 +# Homepage (blog): http://post.darkarsenic.com/ +# //blog.darkarsenic.com/ +# +# Coded in IDLE, tested in Blender 2.59. +# Search for "@todo" to quickly find sections that need work. +# +# ##### BEGIN GPL LICENSE BLOCK ##### +# +# The Blender Rock Creation tool is for rapid generation of mesh rocks in Blender. +# Copyright (C) 2011 Paul Marshall +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# ##### END GPL LICENSE BLOCK ##### + +from mathutils import Vector + +class Retainers: + def __init__(self,G,w,h,wP,wT,hR,n, rEnable, lEnable): + self.G = G #General + self.w=w #retainer width + self.h=h #retainer height + self.wP=wP #post width + self.wT=wT #tread width + self.nR=n #number of retainers + self.sp=hR/float(n+1) #retainer spacing + self.rEnable = rEnable + self.lEnable = lEnable + self.Create() + + def Create(self): + for i in range(self.nR): + coords = [] + offset=(i+1)*Vector([0,0,self.sp]) + coords.append(offset) + coords.append(self.G.stop + offset) + coords.append(offset + Vector([0,self.w,0])) + coords.append(self.G.stop + offset + Vector([0,self.w,0])) + for j in range(4): + coords.append(coords[j] + Vector([0,0,self.h])) + #centre in posts + for j in coords: + j += Vector([0,0.5*(self.wP-self.w),0]) + if self.rEnable: + self.G.Make_mesh(coords, self.G.faces, 'retainers') + if self.lEnable: + #make retainer on other side + for j in coords: + j += Vector([0,self.wT-self.wP,0]) + self.G.Make_mesh(coords,self.G.faces, 'retainers') diff --git a/add_mesh_stairs/stairbuilder.py b/add_mesh_stairs/stairbuilder.py new file mode 100644 index 00000000..44f8ed02 --- /dev/null +++ b/add_mesh_stairs/stairbuilder.py @@ -0,0 +1,484 @@ +# Stairs and railing creator script for blender 2.49 +# Author: Nick van Adium +# 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. +# +#----------------------------------------------------------- +# +# Converted to Blender 2.5: +# - Still uses NumPy. +# - Classes are basically copy-paste from the original code +# - New Make_mesh copied from BrikBot's rock generator +# - Implemented standard add mesh GUI. +# @todo: +# - global vs. local needs cleaned up. +# - Join separate stringer objects and then clean up the mesh. +# - Put all objects into a group. +# - Generate left/right posts/railings/retainers separatly with +# option to disable just the left/right. +# - Add wall railing type as an option for left/right +# - Add different rail styles (profiles). Select with enum. +# - Should have a non-NumPy code path for cross-compatability. +# - Could be another file with equivalent classes/functions? +# Then we would just import from there instead of from +# NumPy without having to change the actual code. It +# would instead be a "try-except" block that trys to use +# NumPy. +# - Would like to add additional staircase types. +# - Spiral staircase +# - "L" staircase +# - "T" staircase +# +# Last Modified By: Paul "brikbot" Marshall +# Last Modification: August 29, 2011 + +#----------------------------------------------------------- +# BEGIN NEW B2.5/Py3.2 CODE +import bpy +from add_mesh_stairs.general import General +from add_mesh_stairs.post import Posts +from add_mesh_stairs.rail import Rails +from add_mesh_stairs.retainer import Retainers +from add_mesh_stairs.stringer import Stringer +from add_mesh_stairs.tread import Treads +from bpy.props import (BoolProperty, + EnumProperty, + IntProperty, + FloatProperty) +from mathutils import Vector + +global G +global typ +global typ_s +global typ_t +global rise +global run + +class stairs(bpy.types.Operator): + '''Add stair objects''' + bl_idname = "mesh.stairs" + bl_label = "Add Stairs" + bl_options = {'REGISTER', 'UNDO'} + bl_description = "Add stairs" + + # Stair types for enum: + id1 = ("id1", "Freestanding", "Generate a freestanding staircase.") + id2 = ("id2", "Housed-Open", "Generate a housed-open staircase.") + id3 = ("id3", "Box", "Generate a box staircase.") + id4 = ("id4", "Circular", "Generate a circular or spiral staircase.") + + # Tread types for enum: + tId1 = ("tId1", "Classic", "Generate wooden style treads") + tId2 = ("tId2", "Basic Steel", "Generate common steel style treads") + tId3 = ("tId3", "Bar 1", "Generate bar/slat steel treads") + tId4 = ("tId4", "Bar 2", "Generate bar-grating steel treads") + tId5 = ("tId5", "Bar 3", "Generate bar-support steel treads") + + # Stringer types for enum: + sId1 = ("sId1", "Classic", "Generate a classic style stringer") + sId2 = ("sId2", "I-Beam", "Generate a steel I-beam stringer") + sId3 = ("sId3", "C-Beam", "Generate a C-channel style stringer") + + typ = EnumProperty(name = "Type", + description = "Type of staircase to generate", + items = [id1, id2, id3, id4]) + + rise = FloatProperty(name = "Rise", + description = "Single tread rise", + min = 0.0, max = 1024.0, + default = 0.20) + run = FloatProperty(name = "Run", + description = "Single tread run", + min = 0.0, max = 1024.0, + default = 0.30) + + #for circular + rad1 = FloatProperty(name = "Inner Radius", + description = "Inner radius for circular staircase", + min = 0.0, max = 1024.0, + default = 0.2) + rad2 = FloatProperty(name = "Outer Radius", + description = "Outer radius for circular staircase", + min = 0.0001, max = 1024.0001, + default = 0.5) + deg = IntProperty(name = "Degrees", + description = "Degrees per step", + min = 5, max = 45, step = 5, + default = 20) + center = BoolProperty(name = "Center Pillar", + description = "Generate a central pillar", + default = False) + + #for treads + make_treads = BoolProperty(name = "Make Treads", + description = "Enable tread generation", + default = True) + tread_w = FloatProperty(name = "Tread Width", + description = "Width of each generated tread", + min = 0.0001, max = 1024.0, + default = 1.2) + tread_h = FloatProperty(name = "Tread Height", + description = "Height of each generated tread", + min = 0.0001, max = 1024.0, + default = 0.04) + tread_t = FloatProperty(name = "Tread Toe", + description = "Toe (aka \"nosing\") of each generated tread", + min = 0.0, max = 10.0, + default = 0.03) + tread_o = FloatProperty(name = "Tread Overhang", + description = "How much tread \"overhangs\" the sides", + min = 0.0, max = 1024.0, + default = 0.025) + tread_n = IntProperty(name = "Number of Treads", + description = "How many treads to generate", + min = 1, max = 1024, + default = 10) + typ_t = EnumProperty(name = "Tread Type", + description = "Type/style of treads to generate", + items = [tId1, tId2, tId3, tId4, tId5]) + tread_tk = FloatProperty(name = "Thickness", + description = "Thickness of the treads", + min = 0.0001, max = 10.0, + default = 0.02) + tread_sec = IntProperty(name = "Sections", + description = "Number of sections to use for tread", + min = 1, max = 1024, + default = 5) + tread_sp = IntProperty(name = "Spacing", + description = "Total spacing between tread sections as a percentage of total tread width", + min = 0, max = 80, + default = 5) + tread_sn = IntProperty(name = "Crosses", + description = "Number of cross section supports", + min = 2, max = 1024, + default = 4) + + #for posts + make_posts = BoolProperty(name = "Make Posts", + description = "Enable post generation", + default = True) + post_d = FloatProperty(name = "Post Depth", + description = "Depth of generated posts", + min = 0.0001, max = 10.0, + default = 0.04) + post_w = FloatProperty(name = "Post Width", + description = "Width of generated posts", + min = 0.0001, max = 10.0, + default = 0.04) + post_n = IntProperty(name = "Number of Posts", + description = "Number of posts to generated", + min = 1, max = 1024, + default = 5) + + #for railings + make_railings = BoolProperty(name = "Make Railings", + description = "Generate railings", + default = True) + rail_w = FloatProperty(name = "Railings Width", + description = "Width of railings to generate", + min = 0.0001, max = 10.0, + default = 0.12) + rail_t = FloatProperty(name = "Railings Thickness", + description = "Thickness of railings to generate", + min = 0.0001, max = 10.0, + default = 0.03) + rail_h = FloatProperty(name = "Railings Height", + description = "Height of railings to generate", + min = 0.0001, max = 10.0, + default = 0.90) + + #for retainers + make_retainers = BoolProperty(name = "Make Retainers", + description = "Generate retainers", + default = True) + ret_w = FloatProperty(name = "Retainer Width", + description = "Width of generated retainers", + min = 0.0001, max = 10.0, + default = 0.01) + ret_h = FloatProperty(name = "Retainer Height", + description = "Height of generated retainers", + min = 0.0001, max = 10.0, + default = 0.01) + ret_n = IntProperty(name = "Number of Retainers", + description = "Number of retainers to generated", + min = 1, max = 1024, + default = 3) + + #for stringer + make_stringer = BoolProperty(name = "Make Stringer", + description = "Generate stair stringer", + default = True) + typ_s = EnumProperty(name = "Stringer Type", + description = "Type/style of stringer to generate", + items = [sId1, sId2, sId3]) + string_n = IntProperty(name = "Number of Stringers", + description = "Number of stringers to generate", + min = 1, max = 10, + default = 1) + string_w = FloatProperty(name = "Stringer width", + description = "Width of stringer as a percentage of tread width", + min = 0.0001, max = 100.0, + default = 15.0) + string_h = FloatProperty(name = "Stringer Height", + description = "Height of the stringer", + min = 0.0001, max = 100.0, + default = 0.3) + string_tw = FloatProperty(name = "Web Thickness", + description = "Thickness of the beam's web as a percentage of width", + min = 0.0001, max = 100.0, + default = 25.0) + string_tf = FloatProperty(name = "Flange Thickness", + description = "Thickness of the flange", + min = 0.0001, max = 100.0, + default = 0.05) + string_tp = FloatProperty(name = "Flange Taper", + description = "Flange thickness taper as a percentage", + min = 0.0, max = 100.0, + default = 0.0) + string_g = BoolProperty(name = "Floating", + description = "Cut bottom of strigner to be a \"floating\" section", + default = False) + + use_original = BoolProperty(name = "Use legacy method", + description = "Use the Blender 2.49 legacy method for stair generation", + default = True) + rEnable = BoolProperty(name = "Right Details", + description = "Generate right side details (posts/rails/retainers)", + default = True) + lEnable = BoolProperty(name = "Left Details", + description = "Generate left side details (posts/rails/retainers)", + default = True) + + # Draw the GUI: + def draw(self, context): + layout = self.layout + box = layout.box() + box.prop(self, 'typ') + box = layout.box() + box.prop(self, 'rise') + if self.typ != "id4": + box.prop(self, 'run') + else: + box.prop(self, 'deg') + box.prop(self, 'rad1') + box.prop(self, 'rad2') + box.prop(self, 'center') + if self.typ == "id1": + box.prop(self, 'use_original') + if not self.use_original: + box.prop(self, 'rEnable') + box.prop(self, 'lEnable') + else: + box.prop(self, 'rEnable') + box.prop(self, 'lEnable') + + # Treads + box = layout.box() + box.prop(self, 'make_treads') + if self.make_treads: + if not self.use_original: + box.prop(self, 'typ_t') + else: + self.typ_t = "tId1" + box.prop(self, 'tread_w') + box.prop(self, 'tread_h') + box.prop(self, 'tread_t') + if self.typ != "id2": + box.prop(self, 'tread_o') + else: + self.tread_o = 0.0 + box.prop(self, 'tread_n') + if self.typ_t != "tId1": + box.prop(self, 'tread_tk') + box.prop(self, 'tread_sec') + if self.tread_sec > 1 and self.typ_t not in ["tId3", "tId4"]: + box.prop(self, 'tread_sp') + if self.typ_t in ["tId3", "tId4", "tId5"]: + box.prop(self, 'tread_sn') + + # Posts + box = layout.box() + box.prop(self, 'make_posts') + if self.make_posts: + box.prop(self, 'post_d') + box.prop(self, 'post_w') + box.prop(self, 'post_n') + + # Railings + box = layout.box() + box.prop(self, 'make_railings') + if self.make_railings: + box.prop(self, 'rail_w') + box.prop(self, 'rail_t') + box.prop(self, 'rail_h') + + # Retainers + box = layout.box() + box.prop(self, 'make_retainers') + if self.make_retainers: + box.prop(self, 'ret_w') + box.prop(self, 'ret_h') + box.prop(self, 'ret_n') + + # Stringers + box = layout.box() + if self.typ != "id2": + box.prop(self, 'make_stringer') + else: + self.make_stringer = True + if self.make_stringer: + if not self.use_original: + box.prop(self, 'typ_s') + else: + self.typ_s = "sId1" + box.prop(self, 'string_w') + if self.typ == "id1": + if self.typ_s == "sId1" and not self.use_original: + box.prop(self, 'string_n') + elif self.typ_s in ["sId2", "sId3"]: + box.prop(self, 'string_n') + box.prop(self, 'string_h') + box.prop(self, 'string_tw') + box.prop(self, 'string_tf') + box.prop(self, 'string_tp') + box.prop(self, 'string_g') + elif self.typ == "id2": + if self.typ_s == "sId2": + box.prop(self, 'string_tw') + box.prop(self, 'string_tf') + + # Tread support: +## if self.make_stringer and typ_s in ["sId2", "sId3"]: + + def execute(self, context): + global G + global typ + global typ_s + global typ_t + global rise + global run + typ = self.typ + typ_s = self.typ_s + typ_t = self.typ_t + rise = self.rise + run = self.run + G=General(rise,run,self.tread_n) + if self.make_treads: + Treads(G, + typ, + typ_t, + run, + self.tread_w, + self.tread_h, + self.run, + self.rise, + self.tread_t, + self.tread_o, + self.tread_n, + self.tread_tk, + self.tread_sec, + self.tread_sp, + self.tread_sn) + if self.make_posts and (self.rEnable or self.lEnable): + Posts(G, + rise, + run, + self.post_d, + self.post_w, + self.tread_w, + self.post_n, + self.rail_h, + self.rail_t, + self.rEnable, + self.lEnable) + if self.make_railings and (self.rEnable or self.lEnable): + Rails(G, + self.rail_w, + self.rail_t, + self.rail_h, + self.tread_t, + self.post_w, + self.post_d, + self.tread_w, + self.rEnable, + self.lEnable) + if self.make_retainers and (self.rEnable or self.lEnable): + Retainers(G, + self.ret_w, + self.ret_h, + self.post_w, + self.tread_w, + self.rail_h, + self.ret_n, + self.rEnable, + self.lEnable) + if self.make_stringer: + if typ == "id1" and self.use_original: + Stringer(G, + typ, + typ_s, + rise, + run, + self.string_w, + self.string_h, + self.tread_n, + self.tread_h, + self.tread_w, + self.tread_t, + self.tread_o, + self.string_tw, + self.string_tf, + not self.string_g, + self.string_tp) + elif typ == "id3": + Stringer(G, + typ, + typ_s, + rise, + run, + 100, + self.string_h, + self.tread_n, + self.tread_h, + self.tread_w, + self.tread_t, + self.tread_o, + self.string_tw, + self.string_tf, + self.string_tp, + not self.string_g, + 1, False) + else: + Stringer(G, + typ, + typ_s, + rise, + run, + self.string_w, + self.string_h, + self.tread_n, + self.tread_h, + self.tread_w, + self.tread_t, + self.tread_o, + self.string_tw, + self.string_tf, + self.string_tp, + not self.string_g, + self.string_n, + self.use_original) + return {'FINISHED'} diff --git a/add_mesh_stairs/stringer.py b/add_mesh_stairs/stringer.py new file mode 100644 index 00000000..eedbc988 --- /dev/null +++ b/add_mesh_stairs/stringer.py @@ -0,0 +1,291 @@ +# Stairbuilder - Stringer generation +# +# Generates stringer mesh for stair generation. +# Stair Type (typ): +# - id1 = Freestanding staircase +# - id2 = Housed-open staircase +# - id3 = Box staircase +# - id4 = Circular staircase +# Stringer Type (typ_s): +# - sId1 = Classic +# - sId2 = I-Beam +# - sId3 = C-Beam +# +# Paul "BrikBot" Marshall +# Created: September 19, 2011 +# Last Modified: September 20, 2011 +# Homepage (blog): http://post.darkarsenic.com/ +# //blog.darkarsenic.com/ +# +# Coded in IDLE, tested in Blender 2.59. +# Search for "@todo" to quickly find sections that need work. +# +# ##### BEGIN GPL LICENSE BLOCK ##### +# +# The Blender Rock Creation tool is for rapid generation of mesh rocks in Blender. +# Copyright (C) 2011 Paul Marshall +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# ##### END GPL LICENSE BLOCK ##### + +from math import atan, cos, tan +from mathutils import Vector +from mathutils.geometry import (intersect_line_plane, + intersect_line_line) + +class Stringer: + def __init__(self,G,typ,typ_s,rise,run,w,h,nT,hT,wT,tT,tO,tw,tf,tp,g,nS = 1,notMulti=True): + self.G = G #General + self.typ = typ # Stair type + self.typ_s = typ_s # Stringer type + self.rise = rise #Stair rise + self.run = run #Stair run + if notMulti: + self.w=w/100 #stringer width + else: + self.w=(wT*(w/100))/nS + self.h = h #stringer height + self.nT=nT #number of treads + self.hT=hT #tread height + self.wT=wT #tread width + self.tT=tT #tread toe + self.tO = tO #Tread overhang + self.tw = self.w * (tw / 100) #stringer web thickness + self.tf = tf #stringer flange thickness + self.tp = 1 - (tp / 100) #stringer flange taper + self.g = g #does stringer intersect the ground? + self.nS=nS #number of stringers + # Default stringer object (classic / sId1): + self.faces1=[[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],[2,3,9,8],[3,4,10,9],[4,5,11,10]] + # Box stair type stringer: + self.faces2=[[0,1,7,6],[1,3,9,7],[3,4,10,9],[4,10,11,5],[5,11,8,2], + [2,8,6,0],[0,1,2],[1,2,5,3],[3,4,5],[6,7,8],[7,8,11,9],[9,10,11]] + # I-beam stringer (I-Beam / sId2 / Taper < 100%): + # @todo: faces are not complete nor are they layed out correctly. Check verts also. + 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], + [6,7,23,22],[7,8,24,23],[8,9,25,24],[9,10,26,25],[10,11,27,26], + [11,12,28,27],[12,13,29,28],[13,14,30,29],[14,15,31,30],[15,0,16,31], + [0,1,2,15],[2,11,14,15],[11,12,13,14],[2,3,10,11],[3,4,5,6],[3,6,7,10], + [7,8,9,10],[16,17,18,31],[18,27,30,31],[27,28,29,30],[18,19,26,27], + [19,20,21,22],[19,22,23,26],[23,24,25,26]] + # I-beam stringer (I-Beam / sId2 / Taper = 100%): + 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], + [6,7,15,14],[7,0,8,15],[0,1,6,7],[1,2,5,6],[2,3,4,5],[8,9,14,15], + [9,10,13,14],[10,11,12,13]] + # I-beam stringer for housed-open stringed: + self.faces3c=[[0,1,2,7],[2,3,6,7],[3,4,5,6],[1,2,23,16],[2,3,22,23],[3,4,21,22], + [16,17,18,23],[18,19,22,23],[19,20,21,22],[17,8,15,18],[18,15,14,19], + [19,14,13,20],[8,9,10,15],[10,11,14,15],[11,12,13,14],[9,10,53,52], + [10,11,54,53],[11,12,55,54],[52,53,61,60],[53,54,62,61],[54,55,63,62], + [60,61,34,33],[61,62,35,34],[62,63,36,35],[32,33,34,39],[34,35,38,39], + [35,36,37,38],[41,32,39,42],[42,39,38,43],[43,38,37,44],[40,41,42,47], + [42,43,46,47],[43,44,45,46],[25,26,47,40],[26,27,46,47],[27,28,45,46], + [24,25,26,31],[26,27,30,31],[27,28,29,30],[24,31,57,56],[31,30,58,57], + [30,29,59,58],[48,49,57,56],[49,50,58,57],[50,51,59,58],[0,7,49,48], + [7,6,50,49],[6,5,51,50],[0,1,16,48],[16,40,56,48],[24,25,40,56], + [16,17,41,40],[8,9,52,17],[17,52,60,41],[32,33,60,41],[12,13,20,55], + [20,44,63,55],[37,44,63,36],[20,21,45,44],[28,29,51,21],[21,51,59,45], + [28,45,59,29],[4,5,51,21]] + # C-beam stringer (C-Beam / sId3): + self.faces4=[[]] + self.Create() + + def Create(self): + if self.typ == "id1": + if self.typ_s == "sId1": + offset = (self.wT / (self.nS + 1)) - (self.w / 2) + for i in range(self.nS): + for j in range(self.nT): + coords = [] + coords.append(Vector([0, offset, -self.rise])) + coords.append(Vector([self.run, offset, -self.rise])) + coords.append(Vector([0, offset, -self.hT])) + coords.append(Vector([self.run, offset, -self.hT])) + coords.append(Vector([self.run, offset, 0])) + coords.append(Vector([self.run * 2, offset, 0])) + for k in range(6): + coords.append(coords[k]+Vector([0, self.w, 0])) + for k in coords: + k += j*Vector([self.run, 0, self.rise]) + self.G.Make_mesh(coords,self.faces1,'stringer') + offset += self.wT / (self.nS + 1) + elif self.typ_s == "sId2": + self.IBeam() + elif self.typ == "id2": + if self.typ_s == "sId1": + coords = [] + coords.append(Vector([-self.tT, -self.w, -self.rise])) + coords.append(Vector([self.hT / self.G.slope, -self.w, -self.rise])) + coords.append(Vector([-self.tT, -self.w, 0])) + coords.append(Vector([self.nT * self.run, -self.w, + ((self.nT - 1) * self.rise) - self.hT])) + coords.append(Vector([self.nT * self.run, -self.w, self.nT * self.rise])) + coords.append(Vector([(self.nT * self.run) - self.tT, -self.w, + self.nT * self.rise])) + for i in range(6): + coords.append(coords[i] + Vector([0, self.w, 0])) + self.G.Make_mesh(coords, self.faces2, 'stringer') + for i in coords: + i += Vector([0, self.w + self.wT, 0]) + self.G.Make_mesh(coords, self.faces2, 'stringer') + elif self.typ_s == "sId2": + self.HousedIBeam() + elif self.typ == "id3": + h = (self.rise - self.hT) - self.rise #height of top section + for i in range(self.nT): + coords = [] + coords.append(Vector([i * self.run,0,-self.rise])) + coords.append(Vector([(i + 1) * self.run,0,-self.rise])) + coords.append(Vector([i * self.run,0,h + (i * self.rise)])) + coords.append(Vector([(i + 1) * self.run,0,h + (i * self.rise)])) + for j in range(4): + coords.append(coords[j] + Vector([0,self.wT,0])) + self.G.Make_mesh(coords, self.G.faces, 'stringer') + + def IBeam(self): + mid = self.w / 2 + web = self.tw / 2 + # Bottom of the stringer: + baseZ = -self.rise - self.hT - self.h + # Top of the strigner: + topZ = -self.rise - self.hT + # Vertical taper amount: + taper = self.tf * self.tp + offset = (self.wT / (self.nS + 1)) - mid + # taper < 100%: + if self.tp > 0: + for i in range(self.nS): + coords = [] + coords.append(Vector([0, offset, baseZ])) + coords.append(Vector([0, offset, baseZ + taper])) + coords.append(Vector([0, offset + (mid - web), baseZ + self.tf])) + coords.append(Vector([0, offset + (mid - web), topZ - self.tf])) + coords.append(Vector([0, offset, topZ - taper])) + coords.append(Vector([0, offset, topZ])) + coords.append(Vector([0, offset + (mid - web), topZ])) + coords.append(Vector([0, offset + (mid + web), topZ])) + coords.append(Vector([0, offset + self.w, topZ])) + coords.append(Vector([0, offset + self.w, topZ - taper])) + coords.append(Vector([0, offset + (mid + web), topZ - self.tf])) + coords.append(Vector([0, offset + (mid + web), baseZ + self.tf])) + coords.append(Vector([0, offset + self.w, baseZ + taper])) + coords.append(Vector([0, offset + self.w, baseZ])) + coords.append(Vector([0, offset + (mid + web), baseZ])) + coords.append(Vector([0, offset + (mid - web), baseZ])) + for j in range(16): + coords.append(coords[j]+Vector([self.run * self.nT, 0, self.rise * self.nT])) + # If the bottom meets the ground: + # Bottom be flat with the xy plane, but shifted down. + # Either project onto the plane along a vector (hard) or use the built in + # interest found in mathutils.geometry (easy). Using intersect: + if self.g: + for j in range(16): + coords[j] = intersect_line_plane(coords[j], coords[j + 16], + Vector([0, 0, topZ]), + Vector([0, 0, 1])) + self.G.Make_mesh(coords, self.faces3a, 'stringer') + offset += self.wT / (self.nS + 1) + # taper = 100%: + else: + for i in range(self.nS): + coords = [] + coords.append(Vector([0, offset, baseZ])) + coords.append(Vector([0, offset + (mid - web), baseZ + self.tf])) + coords.append(Vector([0, offset + (mid - web), topZ - self.tf])) + coords.append(Vector([0, offset, topZ])) + coords.append(Vector([0, offset + self.w, topZ])) + coords.append(Vector([0, offset + (mid + web), topZ - self.tf])) + coords.append(Vector([0, offset + (mid + web), baseZ + self.tf])) + coords.append(Vector([0, offset + self.w, baseZ])) + for j in range(8): + coords.append(coords[j]+Vector([self.run * self.nT, 0, self.rise * self.nT])) + self.G.Make_mesh(coords, self.faces3b, 'stringer') + offset += self.wT / (self.nS + 1) + + return {'FINISHED'} + + def HousedIBeam(self): + webOrth = Vector([self.rise, 0, -self.run]).normalized() + webHeight = Vector([self.run + self.tT, 0, -self.hT]).project(webOrth).length + vDelta_1 = self.tf * tan(self.G.angle) + vDelta_2 = (self.rise * (self.nT - 1)) - (webHeight + self.tf) + flange_y = (self.w - self.tw) / 2 + front = -self.tT - self.tf + outer = -self.tO - self.tw - flange_y + + coords = [] + if self.tp > 0: + # Upper-Outer flange: + coords.append(Vector([front, outer, -self.rise])) + coords.append(Vector([-self.tT, outer, -self.rise])) + coords.append(Vector([-self.tT, outer, 0])) + coords.append(Vector([(self.run * (self.nT - 1)) - self.tT, outer, + self.rise * (self.nT - 1)])) + coords.append(Vector([self.run * self.nT, outer, + self.rise * (self.nT - 1)])) + coords.append(Vector([self.run * self.nT, outer, + (self.rise * (self.nT - 1)) + self.tf])) + coords.append(Vector([(self.run * (self.nT - 1)) - self.tT, outer, + (self.rise * (self.nT - 1)) + self.tf])) + coords.append(Vector([front, outer, self.tf - vDelta_1])) + # Lower-Outer flange: + coords.append(coords[0] + Vector([self.tf + webHeight, 0, 0])) + coords.append(coords[1] + Vector([self.tf + webHeight, 0, 0])) + coords.append(intersect_line_line(coords[9], + coords[9] - Vector([0, 0, 1]), + Vector([self.run, 0, -self.hT - self.tf]), + Vector([self.run * 2, 0, self.rise - self.hT - self.tf]))[0]) + coords.append(Vector([(self.run * self.nT) - ((webHeight - self.hT) / tan(self.G.angle)), + outer, vDelta_2])) + coords.append(coords[4] - Vector([0, 0, self.tf + webHeight])) + coords.append(coords[5] - Vector([0, 0, self.tf + webHeight])) + coords.append(coords[11] + Vector([0, 0, self.tf])) + coords.append(intersect_line_line(coords[8], + coords[8] - Vector([0, 0, 1]), + Vector([self.run, 0, -self.hT]), + Vector([self.run * 2, 0, self.rise - self.hT]))[0]) + # Outer web: + coords.append(coords[1] + Vector([0, flange_y, 0])) + coords.append(coords[8] + Vector([0, flange_y, 0])) + coords.append(coords[15] + Vector([0, flange_y, 0])) + coords.append(coords[14] + Vector([0, flange_y, 0])) + coords.append(coords[13] + Vector([0, flange_y, 0])) + coords.append(coords[4] + Vector([0, flange_y, 0])) + coords.append(coords[3] + Vector([0, flange_y, 0])) + coords.append(coords[2] + Vector([0, flange_y, 0])) + # Upper-Inner flange and lower-inner flange: + for i in range(16): + coords.append(coords[i] + Vector([0, self.w, 0])) + # Inner web: + for i in range(8): + coords.append(coords[i + 16] + Vector([0, self.tw, 0])) + # Mid nodes to so faces will be quads: + for i in [0,7,6,5,9,10,11,12]: + coords.append(coords[i] + Vector([0, flange_y, 0])) + for i in range(8): + coords.append(coords[i + 48] + Vector([0, self.tw, 0])) + + self.G.Make_mesh(coords, self.faces3c, 'stringer') + + for i in coords: + i += Vector([0, (self.tO * 2) + self.wT + self.tf, 0]) + + self.G.Make_mesh(coords, self.faces3c, 'stringer') + + return {'FINISHED'} + + def CBeam(self): + return {'FINISHED'} diff --git a/add_mesh_stairs/tread.py b/add_mesh_stairs/tread.py new file mode 100644 index 00000000..7de9b7f0 --- /dev/null +++ b/add_mesh_stairs/tread.py @@ -0,0 +1,212 @@ +# Stairbuilder - Tread generation +# +# Generates treads for stair generation. +# Stair Type (typ): +# - id1 = Freestanding staircase +# - id2 = Housed-open staircase +# - id3 = Box staircase +# - id4 = Circular staircase +# Tread Type (typ_t): +# - tId1 = Classic +# - tId2 = Basic Steel +# - tId3 = Bar 1 +# - tId4 = Bar 2 +# - tId5 = Bar 3 +# +# Paul "BrikBot" Marshall +# Created: September 19, 2011 +# Last Modified: September 20, 2011 +# Homepage (blog): http://post.darkarsenic.com/ +# //blog.darkarsenic.com/ +# +# Coded in IDLE, tested in Blender 2.59. +# Search for "@todo" to quickly find sections that need work. +# +# ##### BEGIN GPL LICENSE BLOCK ##### +# +# The Blender Rock Creation tool is for rapid generation of mesh rocks in Blender. +# Copyright (C) 2011 Paul Marshall +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# ##### END GPL LICENSE BLOCK ##### + +from copy import copy +from math import sqrt +from mathutils import Vector + +class Treads: + def __init__(self,G,typ,typ_t,run,w,h,d,r,toe,o,n,tk,sec,sp,sn): + self.G = G #General + self.typ = typ #Stair type + self.typ_t = typ_t #Tread type + self.run = run #Stair run + 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.o=o #tread side overhang + self.n=n #number of treads + self.tk=tk #thickness of tread metal + self.sec=sec #metal sections for tread + if sec != 1 and typ_t not in ["tId4", "tId5"]: + self.sp=((d+toe)*(sp/100))/(sec-1) #spacing between sections (% of depth) + elif typ_t in ["tId4", "tId5"]: + self.sp=sp/100 #keep % value + else: + self.sp=0 + self.sn=sn #number of cross sections + self.tId2_faces = [[0,1,2,3],[0,3,4,5],[4,5,6,7],[6,7,8,9],[8,9,10,11], + [12,13,14,15],[12,15,16,17],[16,17,18,19], + [18,19,20,21],[20,21,22,23],[0,1,13,12],[1,2,14,13], + [2,3,15,14],[3,4,16,15],[4,7,19,16],[7,8,20,19], + [8,11,23,20],[11,10,22,23],[10,9,21,22],[9,6,18,21], + [6,5,17,18],[5,0,12,17]] + self.out_faces = [[0,2,3,1],[0,2,10,8],[9,11,3,1],[9,11,10,8], + [2,6,7,3],[2,6,14,10],[11,15,7,3],[11,15,14,10], + [0,4,5,1],[0,4,12,8],[9,13,5,1],[9,13,12,8], + [4,6,7,5],[4,6,14,12],[13,15,14,12],[13,15,7,5]] + self.Create() + + def Create(self): + # Setup the coordinates: + coords = [] + coords2 = [] + coords3 = [] + cross = 0 + cW = 0 + depth = 0 + offset = 0 + height = 0 + if self.typ in ["id1", "id2", "id3"]: + if self.typ_t == "tId1": + coords.append(Vector([-self.t,-self.o,0])) + coords.append(Vector([self.d,-self.o,0])) + coords.append(Vector([-self.t,self.w + self.o,0])) + coords.append(Vector([self.d,self.w + self.o,0])) + for i in range(4): + coords.append(coords[i]+Vector([0,0,-self.h])) + + elif self.typ_t == "tId2": + depth = (self.d + self.t - (self.sec - 1) * self.sp) / self.sec + inset = depth / 4 + tDepth = depth - self.t + coords.append(Vector([-self.t, -self.o, -self.h])) #0 + coords.append(Vector([inset - self.t, -self.o, -self.h])) #1 + coords.append(Vector([inset - self.t, -self.o, -self.h + self.tk])) #2 + coords.append(Vector([self.tk - self.t, -self.o, -self.h + self.tk])) #3 + coords.append(Vector([self.tk - self.t, -self.o, -self.tk])) #4 + coords.append(Vector([-self.t, -self.o, 0])) #5 + coords.append(Vector([tDepth, -self.o, 0])) #6 + coords.append(Vector([tDepth - self.tk, -self.o, -self.tk])) #7 + coords.append(Vector([tDepth - self.tk, -self.o, self.tk - self.h])) #8 + coords.append(Vector([tDepth, -self.o, -self.h])) #9 + coords.append(Vector([tDepth - inset, -self.o, -self.h])) #10 + coords.append(Vector([tDepth - inset, -self.o, -self.h + self.tk])) #11 + for i in range(12): + coords.append(coords[i] + Vector([0, self.w + (2 * self.o), 0])) + + elif self.typ_t in ["tId3", "tId4", "tId5"]: + # Frame: + coords.append(Vector([-self.t,-self.o,-self.h])) + coords.append(Vector([self.d,-self.o,-self.h])) + coords.append(Vector([-self.t,-self.o,0])) + coords.append(Vector([self.d,-self.o,0])) + for i in range(4): + if (i % 2) == 0: + coords.append(coords[i] + Vector([self.tk,self.tk,0])) + else: + coords.append(coords[i] + Vector([-self.tk,self.tk,0])) + for i in range(4): + coords.append(coords[i] + Vector([0,self.w + self.o,0])) + for i in range(4): + coords.append(coords[i + 4] + Vector([0,self.w + self.o - (2 * self.tk),0])) + + # Tread sections: + if self.typ_t == "tId3": + offset = (self.tk * sqrt(2)) / 2 + topset = self.h - offset + self.sp = ((self.d + self.t - (2 * self.tk)) - (offset * (self.sec) + topset)) / (self.sec + 1) + baseX = -self.t + self.sp + self.tk + coords2.append(Vector([baseX, self.tk - self.o, offset - self.h])) + coords2.append(Vector([baseX + offset, self.tk - self.o, -self.h])) + for i in range(2): + coords2.append(coords2[i] + Vector([topset, 0, topset])) + for i in range(4): + coords2.append(coords2[i] + Vector([0, (self.w + self.o) - (2 * self.tk), 0])) + elif self.typ_t in ["tId4", "tId5"]: + offset = ((self.run + self.t) * self.sp) / (self.sec + 1) + topset = (((self.run + self.t) * (1 - self.sp)) - (2 * self.tk)) / self.sec + baseX = -self.t + self.tk + offset + baseY = self.w + self.o - 2 * self.tk + coords2.append(Vector([baseX, -self.o + self.tk, -self.h / 2])) + coords2.append(Vector([baseX + topset, -self.o + self.tk, -self.h / 2])) + coords2.append(Vector([baseX, -self.o + self.tk, 0])) + coords2.append(Vector([baseX + topset, -self.o + self.tk, 0])) + for i in range(4): + coords2.append(coords2[i] + Vector([0, baseY, 0])) + + # Tread cross-sections: + if self.typ_t in ["tId3", "tId4"]: + cW = self.tk + cross = (self.w + (2 * self.o) - (self.sn + 2) * self.tk) / (self.sn + 1) + else: # tId5 + spacing = self.sp ** (1 / 4) + cross = ((2*self.o + self.w) * spacing) / (self.sn + 1) + cW = (-2*self.tk + (2*self.o + self.w) * (1 - spacing)) / self.sn + self.sp = topset + height = -self.h / 2 + baseY = -self.o + self.tk + cross + coords3.append(Vector([-self.t + self.tk, baseY, -self.h])) + coords3.append(Vector([self.d - self.tk, baseY, -self.h])) + coords3.append(Vector([-self.t + self.tk, baseY, height])) + coords3.append(Vector([self.d - self.tk, baseY, height])) + for i in range(4): + coords3.append(coords3[i] + Vector([0, cW, 0])) + + # Make the treads: + for i in range(self.n): + if self.typ_t == "tId1": + self.G.Make_mesh(coords,self.G.faces,'treads') + elif self.typ_t == "tId2": + temp = [] + for j in coords: + temp.append(copy(j)) + for j in range(self.sec): + self.G.Make_mesh(temp, self.tId2_faces, 'treads') + for k in temp: + k += Vector([depth + self.sp, 0, 0]) + elif self.typ_t in ["tId3", "tId4", "tId5"]: + self.G.Make_mesh(coords,self.out_faces,'treads') + temp = [] + for j in coords2: + temp.append(copy(j)) + for j in range(self.sec): + self.G.Make_mesh(temp,self.G.faces,'bars') + for k in temp: + k += Vector([offset + self.sp, 0, 0]) + for j in coords2: + j += Vector([self.d, 0, self.r]) + temp = [] + for j in coords3: + temp.append(copy(j)) + for j in range(self.sn): + self.G.Make_mesh(temp,self.G.faces,'crosses') + for k in temp: + k += Vector([0, cW + cross, 0]) + for j in coords3: + j += Vector([self.d, 0, self.r]) + for j in coords: + j += Vector([self.d,0,self.r]) -- GitLab