mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-20 15:08:51 +00:00
Added more advanced stair generating operator
This commit is contained in:
@@ -81,6 +81,7 @@ classes = (
|
|||||||
ui.BIM_MT_model,
|
ui.BIM_MT_model,
|
||||||
grid.BIM_OT_add_object,
|
grid.BIM_OT_add_object,
|
||||||
stair.BIM_OT_add_object,
|
stair.BIM_OT_add_object,
|
||||||
|
stair.BIM_OT_add_clever_stair,
|
||||||
pie.OpenPieClass,
|
pie.OpenPieClass,
|
||||||
pie.PieUpdateContainer,
|
pie.PieUpdateContainer,
|
||||||
pie.PieAddOpening,
|
pie.PieAddOpening,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
# 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.
|
# This file is part of BlenderBIM Add-on.
|
||||||
#
|
#
|
||||||
@@ -18,12 +18,17 @@
|
|||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
from bpy.types import Operator
|
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 bpy_extras.object_utils import AddObjectHelper, object_data_add
|
||||||
from mathutils import Vector
|
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:
|
if self.number_of_treads <= 0:
|
||||||
self.number_of_treads = 1
|
self.number_of_treads = 1
|
||||||
verts = [
|
verts = [
|
||||||
@@ -69,9 +74,166 @@ class BIM_OT_add_object(Operator, AddObjectHelper):
|
|||||||
length: FloatProperty(name="*Calculated* Length")
|
length: FloatProperty(name="*Calculated* Length")
|
||||||
|
|
||||||
def execute(self, context):
|
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"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
def add_object_button(self, context):
|
def add_object_button(self, context):
|
||||||
self.layout.operator(BIM_OT_add_object.bl_idname, icon="PLUGIN")
|
self.layout.operator(BIM_OT_add_object.bl_idname, icon="PLUGIN")
|
||||||
|
self.layout.operator(BIM_OT_add_clever_stair.bl_idname, icon="PLUGIN")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user