mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-15 18:14:08 +00:00
Fix #3903. Bug where stairs started off with an empty mesh and had a representation added, resulting in an invalid empty point cloud.
Now stairs have should_add_representation=False when creating the IfcStairFlight, and the representation is updated explicitly, similar to how parametric doors and windows etc have their representations updated.
This commit is contained in:
@@ -17,21 +17,17 @@
|
|||||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
|
import json
|
||||||
|
import bmesh
|
||||||
|
import ifcopenshell
|
||||||
|
import blenderbim
|
||||||
|
import blenderbim.tool as tool
|
||||||
|
from mathutils import Vector
|
||||||
|
from bmesh.types import BMVert
|
||||||
from bpy.types import Operator
|
from bpy.types import Operator
|
||||||
from bpy.props import FloatProperty, IntProperty
|
from bpy.props import FloatProperty, IntProperty
|
||||||
from bpy_extras.object_utils import AddObjectHelper, object_data_add
|
from bpy_extras.object_utils import AddObjectHelper, object_data_add
|
||||||
|
|
||||||
import bmesh
|
|
||||||
from bmesh.types import BMVert
|
|
||||||
|
|
||||||
import ifcopenshell
|
|
||||||
from ifcopenshell.util.shape_builder import V, ShapeBuilder
|
from ifcopenshell.util.shape_builder import V, ShapeBuilder
|
||||||
import blenderbim
|
|
||||||
import blenderbim.tool as tool
|
|
||||||
|
|
||||||
from mathutils import Vector
|
|
||||||
from pprint import pprint
|
|
||||||
import json
|
|
||||||
|
|
||||||
|
|
||||||
def add_dumb_stair_object(self, context):
|
def add_dumb_stair_object(self, context):
|
||||||
@@ -106,8 +102,7 @@ def generate_stair_2d_profile(
|
|||||||
if stair_type == "WOOD/STEEL":
|
if stair_type == "WOOD/STEEL":
|
||||||
builder = ShapeBuilder(None)
|
builder = ShapeBuilder(None)
|
||||||
tread_shape = builder.get_rectangle_coords(
|
tread_shape = builder.get_rectangle_coords(
|
||||||
size=V(tread_run, 0, tread_depth),
|
size=V(tread_run, 0, tread_depth), position=V(0, 0, -(tread_depth - tread_rise))
|
||||||
position=V(0, 0, -(tread_depth-tread_rise))
|
|
||||||
)
|
)
|
||||||
tread_offset = V(tread_run, 0, tread_rise)
|
tread_offset = V(tread_run, 0, tread_rise)
|
||||||
|
|
||||||
@@ -116,12 +111,14 @@ def generate_stair_2d_profile(
|
|||||||
vertices.extend(cur_trade_shape)
|
vertices.extend(cur_trade_shape)
|
||||||
|
|
||||||
cur_vertex = i * 4
|
cur_vertex = i * 4
|
||||||
edges.extend([
|
edges.extend(
|
||||||
(cur_vertex, cur_vertex+1),
|
[
|
||||||
(cur_vertex+1, cur_vertex+2),
|
(cur_vertex, cur_vertex + 1),
|
||||||
(cur_vertex+2, cur_vertex+3),
|
(cur_vertex + 1, cur_vertex + 2),
|
||||||
(cur_vertex+3, cur_vertex),
|
(cur_vertex + 2, cur_vertex + 3),
|
||||||
])
|
(cur_vertex + 3, cur_vertex),
|
||||||
|
]
|
||||||
|
)
|
||||||
faces.append(list(range(cur_vertex, cur_vertex + 1)))
|
faces.append(list(range(cur_vertex, cur_vertex + 1)))
|
||||||
|
|
||||||
return (vertices, edges, faces)
|
return (vertices, edges, faces)
|
||||||
@@ -129,36 +126,26 @@ def generate_stair_2d_profile(
|
|||||||
elif stair_type == "GENERIC":
|
elif stair_type == "GENERIC":
|
||||||
vertices.append(Vector([0, 0, 0]))
|
vertices.append(Vector([0, 0, 0]))
|
||||||
|
|
||||||
tread_verts = [
|
tread_verts = [Vector([0, 0, tread_rise]), Vector([tread_run, 0, tread_rise])]
|
||||||
Vector([0, 0, tread_rise]),
|
|
||||||
Vector([tread_run, 0, tread_rise])
|
|
||||||
]
|
|
||||||
tread_offset = Vector([tread_run, 0, tread_rise])
|
tread_offset = Vector([tread_run, 0, tread_rise])
|
||||||
|
|
||||||
for i in range(number_of_risers):
|
for i in range(number_of_risers):
|
||||||
current_tread_verts = [v + tread_offset * i for v in tread_verts]
|
current_tread_verts = [v + tread_offset * i for v in tread_verts]
|
||||||
last_vert_i = len(vertices) - 1
|
last_vert_i = len(vertices) - 1
|
||||||
edges.extend([
|
edges.extend([(last_vert_i, last_vert_i + 1), (last_vert_i + 1, last_vert_i + 2)])
|
||||||
(last_vert_i, last_vert_i + 1),
|
|
||||||
(last_vert_i + 1, last_vert_i + 2)
|
|
||||||
])
|
|
||||||
vertices.extend(current_tread_verts)
|
vertices.extend(current_tread_verts)
|
||||||
|
|
||||||
last_vert_i = len(vertices)
|
last_vert_i = len(vertices)
|
||||||
vertices.append(vertices[-1] * V(1,0,0))
|
vertices.append(vertices[-1] * V(1, 0, 0))
|
||||||
edges.extend([
|
edges.extend([(last_vert_i - 1, last_vert_i), (last_vert_i, 0)])
|
||||||
(last_vert_i - 1, last_vert_i),
|
|
||||||
(last_vert_i, 0)
|
|
||||||
])
|
|
||||||
|
|
||||||
return (vertices, edges, faces)
|
return (vertices, edges, faces)
|
||||||
|
|
||||||
elif stair_type == "CONCRETE":
|
elif stair_type == "CONCRETE":
|
||||||
for i in range(number_of_risers):
|
for i in range(number_of_risers):
|
||||||
vertices.extend([
|
vertices.extend(
|
||||||
Vector((tread_run*i, 0, tread_rise*i)),
|
[Vector((tread_run * i, 0, tread_rise * i)), Vector((tread_run * i, 0, tread_rise * (i + 1)))]
|
||||||
Vector((tread_run*i, 0, tread_rise*(i+1)))
|
)
|
||||||
])
|
|
||||||
cur_vertex = i * 2
|
cur_vertex = i * 2
|
||||||
if i != 0:
|
if i != 0:
|
||||||
edges.append((cur_vertex - 1, cur_vertex))
|
edges.append((cur_vertex - 1, cur_vertex))
|
||||||
@@ -179,11 +166,11 @@ def generate_stair_2d_profile(
|
|||||||
|
|
||||||
# top nib
|
# top nib
|
||||||
if has_top_nib:
|
if has_top_nib:
|
||||||
vertices.append( vertices[number_of_risers * 2] + Vector((0, 0, -top_slab_depth)) )
|
vertices.append(vertices[number_of_risers * 2] + Vector((0, 0, -top_slab_depth)))
|
||||||
vertices.append( vertices[number_of_risers * 2] + Vector(((-top_slab_depth - b) / k, 0, -top_slab_depth)) )
|
vertices.append(vertices[number_of_risers * 2] + Vector(((-top_slab_depth - b) / k, 0, -top_slab_depth)))
|
||||||
last_vertex_i = len(vertices) - 1
|
last_vertex_i = len(vertices) - 1
|
||||||
edges.append( (number_of_risers * 2, last_vertex_i - 1) )
|
edges.append((number_of_risers * 2, last_vertex_i - 1))
|
||||||
edges.append( (last_vertex_i - 1, last_vertex_i) )
|
edges.append((last_vertex_i - 1, last_vertex_i))
|
||||||
else:
|
else:
|
||||||
vertices.append(vertices[number_of_risers * 2] + depth_vector)
|
vertices.append(vertices[number_of_risers * 2] + depth_vector)
|
||||||
last_vertex_i = len(vertices) - 1
|
last_vertex_i = len(vertices) - 1
|
||||||
@@ -200,17 +187,17 @@ def generate_stair_2d_profile(
|
|||||||
vertices.append(vertices[0] + Vector(((-base_slab_depth - b) / k, 0, -base_slab_depth)))
|
vertices.append(vertices[0] + Vector(((-base_slab_depth - b) / k, 0, -base_slab_depth)))
|
||||||
vertices.append(vertices[0] + Vector((0, 0, -base_slab_depth)))
|
vertices.append(vertices[0] + Vector((0, 0, -base_slab_depth)))
|
||||||
last_vertex_i = len(vertices) - 1
|
last_vertex_i = len(vertices) - 1
|
||||||
edges.append( (0, last_vertex_i) )
|
edges.append((0, last_vertex_i))
|
||||||
edges.append( (last_vertex_i - 1, last_vertex_i) )
|
edges.append((last_vertex_i - 1, last_vertex_i))
|
||||||
bottom_nib_end = len(vertices) - 2
|
bottom_nib_end = len(vertices) - 2
|
||||||
|
|
||||||
edges.append( (bottom_nib_end, top_nib_end) )
|
edges.append((bottom_nib_end, top_nib_end))
|
||||||
faces = [list(range(len(vertices)))]
|
faces = [list(range(len(vertices)))]
|
||||||
|
|
||||||
return (vertices, edges, faces)
|
return (vertices, edges, faces)
|
||||||
|
|
||||||
|
|
||||||
def update_stair_modifier(context):
|
def regenerate_stair_mesh(context):
|
||||||
obj = context.active_object
|
obj = context.active_object
|
||||||
props_kwargs = obj.BIMStairProperties.get_props_kwargs()
|
props_kwargs = obj.BIMStairProperties.get_props_kwargs()
|
||||||
vertices, edges, faces = generate_stair_2d_profile(**props_kwargs)
|
vertices, edges, faces = generate_stair_2d_profile(**props_kwargs)
|
||||||
@@ -221,7 +208,7 @@ def update_stair_modifier(context):
|
|||||||
bm.edges.index_update()
|
bm.edges.index_update()
|
||||||
|
|
||||||
new_verts = [bm.verts.new(v) for v in vertices]
|
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]
|
new_edges = [bm.edges.new((new_verts[e[0]], new_verts[e[1]])) for e in edges]
|
||||||
bm.verts.index_update()
|
bm.verts.index_update()
|
||||||
bm.edges.index_update()
|
bm.edges.index_update()
|
||||||
|
|
||||||
@@ -242,6 +229,26 @@ def update_stair_modifier(context):
|
|||||||
obj.data.update()
|
obj.data.update()
|
||||||
|
|
||||||
|
|
||||||
|
def update_stair_representation(obj):
|
||||||
|
body = ifcopenshell.util.representation.get_context(tool.Ifc.get(), "Model", "Body", "MODEL_VIEW")
|
||||||
|
representation = ifcopenshell.api.run(
|
||||||
|
"geometry.add_representation",
|
||||||
|
tool.Ifc.get(),
|
||||||
|
context=body,
|
||||||
|
blender_object=obj,
|
||||||
|
geometry=obj.data,
|
||||||
|
coordinate_offset=tool.Geometry.get_cartesian_point_coordinate_offset(obj),
|
||||||
|
total_items=tool.Geometry.get_total_representation_items(obj),
|
||||||
|
should_force_faceted_brep=tool.Geometry.should_force_faceted_brep(),
|
||||||
|
should_force_triangulation=tool.Geometry.should_force_triangulation(),
|
||||||
|
should_generate_uvs=tool.Geometry.should_generate_uvs(obj),
|
||||||
|
ifc_representation_class=None,
|
||||||
|
profile_set_usage=None,
|
||||||
|
)
|
||||||
|
tool.Model.replace_object_ifc_representation(body, obj, representation)
|
||||||
|
tool.Ifc.finish_edit(obj)
|
||||||
|
|
||||||
|
|
||||||
def update_ifc_stair_props(obj):
|
def update_ifc_stair_props(obj):
|
||||||
"""should be called after new geometry settled
|
"""should be called after new geometry settled
|
||||||
since it's going to update ifc representation
|
since it's going to update ifc representation
|
||||||
@@ -327,7 +334,7 @@ class BIM_OT_add_clever_stair(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
obj.location = spawn_location
|
obj.location = spawn_location
|
||||||
collection = context.view_layer.active_layer_collection.collection
|
collection = context.view_layer.active_layer_collection.collection
|
||||||
collection.objects.link(obj)
|
collection.objects.link(obj)
|
||||||
|
|
||||||
body_context = ifcopenshell.util.representation.get_context(ifc_file, "Model", "Body", "MODEL_VIEW")
|
body_context = ifcopenshell.util.representation.get_context(ifc_file, "Model", "Body", "MODEL_VIEW")
|
||||||
element = blenderbim.core.root.assign_class(
|
element = blenderbim.core.root.assign_class(
|
||||||
tool.Ifc,
|
tool.Ifc,
|
||||||
@@ -335,7 +342,7 @@ class BIM_OT_add_clever_stair(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
tool.Root,
|
tool.Root,
|
||||||
obj=obj,
|
obj=obj,
|
||||||
ifc_class="IfcStairFlight",
|
ifc_class="IfcStairFlight",
|
||||||
should_add_representation=True,
|
should_add_representation=False,
|
||||||
context=body_context,
|
context=body_context,
|
||||||
)
|
)
|
||||||
if tool.Ifc.get_schema() != "IFC2X3":
|
if tool.Ifc.get_schema() != "IFC2X3":
|
||||||
@@ -372,8 +379,9 @@ class AddStair(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
pset=pset,
|
pset=pset,
|
||||||
properties={"Data": json.dumps(stair_data)},
|
properties={"Data": json.dumps(stair_data)},
|
||||||
)
|
)
|
||||||
update_stair_modifier(context)
|
regenerate_stair_mesh(context)
|
||||||
update_ifc_stair_props(obj)
|
update_ifc_stair_props(obj)
|
||||||
|
update_stair_representation(obj)
|
||||||
|
|
||||||
|
|
||||||
class CancelEditingStair(bpy.types.Operator, tool.Ifc.Operator):
|
class CancelEditingStair(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
@@ -388,7 +396,7 @@ class CancelEditingStair(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
props = obj.BIMStairProperties
|
props = obj.BIMStairProperties
|
||||||
# restore previous settings since editing was canceled
|
# restore previous settings since editing was canceled
|
||||||
props.set_props_kwargs_from_ifc_data(data)
|
props.set_props_kwargs_from_ifc_data(data)
|
||||||
update_stair_modifier(context)
|
regenerate_stair_mesh(context)
|
||||||
|
|
||||||
props.is_editing = False
|
props.is_editing = False
|
||||||
|
|
||||||
@@ -407,7 +415,8 @@ class FinishEditingStair(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
|
|
||||||
data = props.get_props_kwargs(convert_to_project_units=True)
|
data = props.get_props_kwargs(convert_to_project_units=True)
|
||||||
props.is_editing = False
|
props.is_editing = False
|
||||||
update_stair_modifier(context)
|
regenerate_stair_mesh(context)
|
||||||
|
update_stair_representation(obj)
|
||||||
|
|
||||||
pset = tool.Pset.get_element_pset(element, "BBIM_Stair")
|
pset = tool.Pset.get_element_pset(element, "BBIM_Stair")
|
||||||
data = json.dumps(data)
|
data = json.dumps(data)
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ from blenderbim.bim.module.model.data import (
|
|||||||
RoofData,
|
RoofData,
|
||||||
)
|
)
|
||||||
from blenderbim.bim.module.model.prop import get_ifc_class
|
from blenderbim.bim.module.model.prop import get_ifc_class
|
||||||
from blenderbim.bim.module.model.stair import update_stair_modifier
|
from blenderbim.bim.module.model.stair import regenerate_stair_mesh
|
||||||
from blenderbim.bim.module.model.window import update_window_modifier_bmesh
|
from blenderbim.bim.module.model.window import update_window_modifier_bmesh
|
||||||
from blenderbim.bim.module.model.door import update_door_modifier_bmesh
|
from blenderbim.bim.module.model.door import update_door_modifier_bmesh
|
||||||
from blenderbim.bim.module.model.railing import update_railing_modifier_bmesh
|
from blenderbim.bim.module.model.railing import update_railing_modifier_bmesh
|
||||||
@@ -267,7 +267,7 @@ class BIM_PT_stair(bpy.types.Panel):
|
|||||||
row = self.layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
for prop_name in props.get_props_kwargs():
|
for prop_name in props.get_props_kwargs():
|
||||||
self.layout.prop(props, prop_name)
|
self.layout.prop(props, prop_name)
|
||||||
update_stair_modifier(context)
|
regenerate_stair_mesh(context)
|
||||||
else:
|
else:
|
||||||
row.operator("bim.enable_editing_stair", icon="GREASEPENCIL", text="")
|
row.operator("bim.enable_editing_stair", icon="GREASEPENCIL", text="")
|
||||||
row.operator("bim.remove_stair", icon="X", text="")
|
row.operator("bim.remove_stair", icon="X", text="")
|
||||||
|
|||||||
@@ -410,7 +410,7 @@ class AddType(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
obj=obj,
|
obj=obj,
|
||||||
predefined_type=predefined_type,
|
predefined_type=predefined_type,
|
||||||
ifc_class="IfcStairFlightType",
|
ifc_class="IfcStairFlightType",
|
||||||
should_add_representation=True,
|
should_add_representation=False,
|
||||||
context=body,
|
context=body,
|
||||||
)
|
)
|
||||||
tool.Blender.select_and_activate_single_object(context, obj)
|
tool.Blender.select_and_activate_single_object(context, obj)
|
||||||
|
|||||||
Reference in New Issue
Block a user