-
Brendon Murphy authoredBrendon Murphy authored
stairbuilder.py 22.80 KiB
# 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: January 29, 2011
#
# ##### BEGIN GPL LICENSE BLOCK #####
#
# Stairbuilder is for quick stair generation.
# 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 #####
#-----------------------------------------------------------
# BEGIN NEW B2.5/Py3.2 CODE
import bpy
from add_mesh_building_objects.general import General
from add_mesh_building_objects.post import Posts
from add_mesh_building_objects.rail import Rails
from add_mesh_building_objects.retainer import Retainers
from add_mesh_building_objects.stringer import Stringer
from add_mesh_building_objects.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,
soft_max = 10.0,
default = 0.25)
rad2 = FloatProperty(name = "Outer Radius",
description = "Outer radius for circular staircase",
min = 0.0, max = 1024.0,
soft_min = 0.015625, soft_max = 32.0,
default = 1.0)
deg = FloatProperty(name = "Degrees",
description = "Number of degrees the stairway rotates",
min = 0.0, max = 92160.0, step = 5.0,
default = 450.0)
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)
#special circular tread properties:
tread_slc = IntProperty(name = "Slices",
description = "Number of slices each tread is composed of",
min = 1, max = 1024,
soft_max = 16,
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_dis = BoolProperty(name = "Distributed",
description = "Use distributed stringers",
default = False)
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:
self.use_original = False
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 and self.typ != "id4":
box.prop(self, 'typ_t')
else:
self.typ_t = "tId1"
if self.typ != "id4":
box.prop(self, 'tread_w')
box.prop(self, 'tread_h')
box.prop(self, 'tread_t')
if self.typ not in ["id2", "id4"]:
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')
elif self.typ == "id4":
box.prop(self, "tread_slc")
# 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')
box.prop(self, 'string_dis')
elif self.typ_s in ["sId2", "sId3"]:
box.prop(self, 'string_n')
box.prop(self, 'string_dis')
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 in ["sId2", "sId3"]:
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:
if typ != "id4":
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)
else:
Treads(G,
typ,
typ_t,
self.deg,
self.rad2,
self.tread_h,
self.run,
self.rise,
self.tread_t,
self.rad1,
self.tread_n,
self.tread_tk,
self.tread_sec,
self.tread_sp,
self.tread_sn,
self.tread_slc)
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,
self.string_tp,
not self.string_g)
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, False)
elif typ == "id4":
Stringer(G,
typ,
typ_s,
rise,
self.deg,
self.string_w,
self.string_h,
self.tread_n,
self.tread_h,
self.rad2 - self.rad1,
self.tread_t,
self.rad1,
self.string_tw,
self.string_tf,
self.string_tp,
not self.string_g,
self.string_n,
self.string_dis,
self.use_original,
self.tread_slc)
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.string_dis,
self.use_original)
return {'FINISHED'}