Added more advanced stair generating operator

This commit is contained in:
Andrej730
2022-11-02 17:31:27 +06:00
parent 35a70a4ae3
commit bd054d4baf
2 changed files with 167 additions and 4 deletions
@@ -81,6 +81,7 @@ classes = (
ui.BIM_MT_model,
grid.BIM_OT_add_object,
stair.BIM_OT_add_object,
stair.BIM_OT_add_clever_stair,
pie.OpenPieClass,
pie.PieUpdateContainer,
pie.PieAddOpening,
@@ -1,5 +1,5 @@
# BlenderBIM Add-on - OpenBIM Blender Add-on
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
# Copyright (C) 2020, 2021, 2022 Dion Moult <dion@thinkmoult.com>, @Andrej730
#
# This file is part of BlenderBIM Add-on.
#
@@ -18,12 +18,17 @@
import bpy
from bpy.types import Operator
from bpy.props import FloatProperty, IntProperty
from bpy.props import FloatProperty, IntProperty, BoolProperty
from bpy_extras.object_utils import AddObjectHelper, object_data_add
from mathutils import Vector
import bmesh
from bmesh.types import BMVert
def add_object(self, context):
from mathutils import Vector
from pprint import pprint
def add_dumb_stair_object(self, context):
if self.number_of_treads <= 0:
self.number_of_treads = 1
verts = [
@@ -69,9 +74,166 @@ class BIM_OT_add_object(Operator, AddObjectHelper):
length: FloatProperty(name="*Calculated* Length")
def execute(self, context):
add_object(self, context)
add_dumb_stair_object(self, context)
return {"FINISHED"}
def create_stair(
operator,
context,
width=1.2,
height=1.0,
number_of_treads=6,
tread_depth=0.25,
tread_run=0.3,
# tread_rise = None, # 0.167
base_slab_depth=0.25,
top_slab_depth=0.25,
has_top_nib=False,
stair_type="CONCRETE",
extrude=True,
):
vertices = []
edges = []
# 2d profile generation
tread_rise = height / number_of_treads
length = tread_run * number_of_treads
for i in range(number_of_treads):
vertices.extend([
Vector((tread_run*i, 0, tread_rise*i)),
Vector((tread_run*i, 0, tread_rise*(i+1)))
])
cur_vertex = i * 2
if i != 0:
edges.append((cur_vertex - 1, cur_vertex))
edges.append((cur_vertex, cur_vertex + 1))
vertices.append(Vector((tread_run * number_of_treads, 0, tread_rise * number_of_treads)))
edges.append((number_of_treads * 2, number_of_treads * 2 - 1))
td_vector = Vector((vertices[2][2], 0, -vertices[2][0])).normalized() * tread_depth
k = tread_rise / tread_run
s0 = vertices[0] + td_vector
b = s0.z - k * s0.x # comes from y = kx + b
# you could use td_vector as depth_vector
# but then stair won't be perpendicular to the X+
# b is kind of vertical tread_depth (along Z+)
depth_vector = Vector((0, 0, b))
# top nib
if has_top_nib:
vertices.append( vertices[number_of_treads * 2] + Vector((0, 0, -top_slab_depth)) )
vertices.append( vertices[number_of_treads * 2] + Vector(((-top_slab_depth - b) / k, 0, -top_slab_depth)) )
last_vertex_i = len(vertices) - 1
edges.append( (number_of_treads * 2, last_vertex_i - 1) )
edges.append( (last_vertex_i - 1, last_vertex_i) )
else:
vertices.append(vertices[number_of_treads * 2] + depth_vector)
last_vertex_i = len(vertices) - 1
edges.append((number_of_treads * 2, last_vertex_i))
top_nib_end = len(vertices) - 1
# bottom nib
if abs(b) <= base_slab_depth:
vertices.append(vertices[0] + depth_vector)
edges.append((0, len(vertices) - 1))
bottom_nib_end = len(vertices) - 1
else:
vertices.append(vertices[0] + Vector(((-base_slab_depth - b) / k, 0, -base_slab_depth)))
vertices.append(vertices[0] + Vector((0, 0, -base_slab_depth)))
last_vertex_i = len(vertices) - 1
edges.append( (0, last_vertex_i) )
edges.append( (last_vertex_i - 1, last_vertex_i) )
bottom_nib_end = len(vertices) - 2
edges.append( (bottom_nib_end, top_nib_end) )
faces = [list(range(len(vertices)))]
# profile generation finished
obj = context.object
bm = bmesh.new()
bm.verts.index_update()
bm.edges.index_update()
new_verts = [bm.verts.new(v) for v in vertices]
new_edges = [bm.edges.new( (new_verts[e[0]], new_verts[e[1]]) ) for e in edges]
bm.verts.index_update()
bm.edges.index_update()
bmesh.ops.contextual_create(bm, geom=new_edges)
if extrude:
bm.faces.ensure_lookup_table()
faces = [bm.faces[0]]
extruded = bmesh.ops.extrude_face_region(bm, geom=faces)
extrusion_vector = Vector((0, 1, 0)) * width
translate_verts = [v for v in extruded["geom"] if isinstance(v, BMVert)]
bmesh.ops.translate(bm, vec=extrusion_vector, verts=translate_verts)
# set origin
prev_cursor_location = bpy.context.scene.cursor.location.copy()
bpy.context.scene.cursor.location = vertices[0]
bpy.ops.object.origin_set(type="ORIGIN_CURSOR", center="MEDIAN")
bpy.context.scene.cursor.location = prev_cursor_location
if context.object.mode == "EDIT":
bmesh.update_edit_mesh(obj.data)
else:
bm.to_mesh(obj.data)
bm.free()
return (obj, tread_rise, length)
def add_object_stair(self, context):
if context.object is None:
self.report({"ERROR"}, "Select object that will be transformed to a stair.")
return
mesh, tread_rise, length = create_stair(
operator=self,
context=context,
stair_type="CONCRETE",
width=self.width,
height=self.height,
number_of_treads=self.number_of_treads,
tread_depth=self.tread_depth,
tread_run=self.tread_run,
base_slab_depth=self.base_slab_depth,
top_slab_depth=self.top_slab_depth,
has_top_nib=self.has_top_nib,
)
self.tread_rise = tread_rise
self.length = length
class BIM_OT_add_clever_stair(Operator):
bl_idname = "mesh.add_clever_stair"
bl_label = "Clever Stair"
bl_options = {"REGISTER", "UNDO"}
width: FloatProperty(name="Width", default=1.2, soft_min=0.01)
height: FloatProperty(name="Height", default=1.0, soft_min=0.01)
number_of_treads: IntProperty(name="Number of Treads (Goings)", default=6, soft_min=1)
tread_depth: FloatProperty(name="Tread Depth", default=0.25, soft_min=0.01)
tread_run: FloatProperty(name="Tread Run", default=0.3, soft_min=0.01)
base_slab_depth: FloatProperty(name="Base slab depth", default=0.25, soft_min=0)
top_slab_depth: FloatProperty(name="Top slab depth", default=0.25, soft_min=0)
has_top_nib: BoolProperty(name="Has top nib", default=True)
tread_rise: FloatProperty(name="*Calculated* Tread Rise")
length: FloatProperty(name="*Calculated* Length")
def execute(self, context):
add_object_stair(self, context)
return {"FINISHED"}
def add_object_button(self, context):
self.layout.operator(BIM_OT_add_object.bl_idname, icon="PLUGIN")
self.layout.operator(BIM_OT_add_clever_stair.bl_idname, icon="PLUGIN")