diff --git a/src/blenderbim/blenderbim/bim/module/model/__init__.py b/src/blenderbim/blenderbim/bim/module/model/__init__.py index 2245e92761..b7d9470cb2 100644 --- a/src/blenderbim/blenderbim/bim/module/model/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/model/__init__.py @@ -36,7 +36,7 @@ from . import ( profile, sverchok_modifier, door, - railing + railing, ) classes = ( diff --git a/src/blenderbim/blenderbim/bim/module/model/data.py b/src/blenderbim/blenderbim/bim/module/model/data.py index 9725901df6..c0c9f4c9e5 100644 --- a/src/blenderbim/blenderbim/bim/module/model/data.py +++ b/src/blenderbim/blenderbim/bim/module/model/data.py @@ -463,7 +463,7 @@ class DoorData: if parameters: parameters["data_dict"] = json.loads(parameters.get("Data", "[]") or "[]") return parameters - + class RailingData: data = {} diff --git a/src/blenderbim/blenderbim/bim/module/model/prop.py b/src/blenderbim/blenderbim/bim/module/model/prop.py index 196ee0029c..28c4f66b68 100644 --- a/src/blenderbim/blenderbim/bim/module/model/prop.py +++ b/src/blenderbim/blenderbim/bim/module/model/prop.py @@ -543,17 +543,15 @@ class BIMDoorProperties(PropertyGroup): kwargs["frame_depth"] = self.frame_depth return kwargs - + class BIMRailingProperties(PropertyGroup): - railing_types = ( - ("FRAMELESS_PANEL", "FRAMELESS_PANEL", ""), - ) + railing_types = (("FRAMELESS_PANEL", "FRAMELESS_PANEL", ""),) railing_added_previously: bpy.props.BoolProperty(default=False) is_editing: bpy.props.IntProperty(default=-1) is_editing_path: bpy.props.BoolProperty(default=False) - + railing_type: bpy.props.EnumProperty(name="Railing Type", items=railing_types, default="FRAMELESS_PANEL") height: bpy.props.FloatProperty(name="Height", default=1.0) thickness: bpy.props.FloatProperty(name="Thickness", default=0.050) diff --git a/src/blenderbim/blenderbim/bim/module/model/railing.py b/src/blenderbim/blenderbim/bim/module/model/railing.py index eb126e9da5..d492704ea8 100644 --- a/src/blenderbim/blenderbim/bim/module/model/railing.py +++ b/src/blenderbim/blenderbim/bim/module/model/railing.py @@ -39,17 +39,19 @@ import json # https://ifc43-docs.standards.buildingsmart.org/IFC/RELEASE/IFC4x3/HTML/lexical/IfcRailing.htm # https://ifc43-docs.standards.buildingsmart.org/IFC/RELEASE/IFC4x3/HTML/lexical/IfcRailingType.htm + def bm_split_edge_at_offset(edge, offset): v0, v1 = edge.verts offset = offset / 2 - edge_len = (v0.co-v1.co).xy.length + edge_len = (v0.co - v1.co).xy.length - split_output_0 = bmesh.utils.edge_split(edge, v0, offset/edge_len) - split_output_1 = bmesh.utils.edge_split(edge, v1, offset/(edge_len-offset)) + split_output_0 = bmesh.utils.edge_split(edge, v0, offset / edge_len) + split_output_1 = bmesh.utils.edge_split(edge, v1, offset / (edge_len - offset)) new_geometry = bm_sort_out_geom(split_output_0 + split_output_1) return new_geometry + def update_railing_modifier_ifc_data(context): obj = context.active_object props = obj.BIMRailingProperties @@ -57,12 +59,12 @@ def update_railing_modifier_ifc_data(context): ifc_file = tool.Ifc.get() # type attributes - element.PredefinedType = 'USERDEFINED' + element.PredefinedType = "USERDEFINED" # occurences attributes occurences = tool.Ifc.get_all_element_occurences(element) for occurence in occurences: occurence.ObjectType = props.railing_type - + # update pset pset_common = tool.Pset.get_element_pset(element, "Pset_RailingCommon") if not pset_common: @@ -77,6 +79,7 @@ def update_railing_modifier_ifc_data(context): }, ) + def update_bbim_railing_pset(element, railing_data): pset = tool.Pset.get_element_pset(element, "BBIM_Railing") if not pset: @@ -84,14 +87,15 @@ def update_bbim_railing_pset(element, railing_data): railing_data = json.dumps(railing_data, default=list) ifcopenshell.api.run("pset.edit_pset", tool.Ifc.get(), pset=pset, properties={"Data": railing_data}) + def update_railing_modifier_bmesh(context): obj = context.object props = obj.BIMRailingProperties if not RailingData.is_loaded: RailingData.load() - path_data = RailingData.data["parameters"]['data_dict']['path_data'] - + path_data = RailingData.data["parameters"]["data_dict"]["path_data"] + si_conversion = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get()) # need to make sure we support edit mode # since users will probably be in edit mode when they'll be changing railing path @@ -100,14 +104,14 @@ def update_railing_modifier_bmesh(context): # generating railing path bm.verts.index_update() bm.edges.index_update() - new_verts = [bm.verts.new(Vector(v) * si_conversion) for v in path_data['verts']] - new_edges = [bm.edges.new( (new_verts[e[0]], new_verts[e[1]]) ) for e in path_data['edges']] + new_verts = [bm.verts.new(Vector(v) * si_conversion) for v in path_data["verts"]] + new_edges = [bm.edges.new((new_verts[e[0]], new_verts[e[1]])) for e in path_data["edges"]] bm.verts.index_update() bm.edges.index_update() if props.is_editing_path: tool.Blender.apply_bmesh(obj.data, bm) - return + return # generating the entire railing height = props.height * si_conversion @@ -119,7 +123,7 @@ def update_railing_modifier_bmesh(context): main_edges = bm.edges[:] for main_edge in main_edges: bm_split_edge_at_offset(main_edge, spacing) - + # thickness # keep track of translated verts so we won't translate the same # vert twice @@ -127,24 +131,24 @@ def update_railing_modifier_bmesh(context): for main_edge in main_edges: v0, v1 = main_edge.verts edge_dissolving_verts.extend([v0, v1]) - - edge_dir = ( (v1.co-v0.co) * V(1,1,0) ).normalized() - ortho_vector = edge_dir.cross( V(0,0,1) ) - extruded_geom = bmesh.ops.extrude_edge_only(bm, edges=[main_edge])['geom'] - extruded_verts = bm_sort_out_geom(extruded_geom)['verts'] - bmesh.ops.translate(bm, vec=ortho_vector * (-thickness/2), verts=extruded_verts) + edge_dir = ((v1.co - v0.co) * V(1, 1, 0)).normalized() + ortho_vector = edge_dir.cross(V(0, 0, 1)) - extruded_geom = bmesh.ops.extrude_edge_only(bm, edges=[main_edge])['geom'] - extruded_verts = bm_sort_out_geom(extruded_geom)['verts'] - bmesh.ops.translate(bm, vec=ortho_vector * (thickness/2), verts=extruded_verts) + extruded_geom = bmesh.ops.extrude_edge_only(bm, edges=[main_edge])["geom"] + extruded_verts = bm_sort_out_geom(extruded_geom)["verts"] + bmesh.ops.translate(bm, vec=ortho_vector * (-thickness / 2), verts=extruded_verts) + + extruded_geom = bmesh.ops.extrude_edge_only(bm, edges=[main_edge])["geom"] + extruded_verts = bm_sort_out_geom(extruded_geom)["verts"] + bmesh.ops.translate(bm, vec=ortho_vector * (thickness / 2), verts=extruded_verts) # dissolve middle edge bmesh.ops.dissolve_edges(bm, edges=[main_edge]) # height - extruded_geom = bmesh.ops.extrude_face_region(bm, geom=bm.faces)['geom'] - extruded_verts = bm_sort_out_geom(extruded_geom)['verts'] + extruded_geom = bmesh.ops.extrude_face_region(bm, geom=bm.faces)["geom"] + extruded_verts = bm_sort_out_geom(extruded_geom)["verts"] extrusion_vector = Vector((0, 0, 1)) * height bmesh.ops.translate(bm, vec=extrusion_vector, verts=extruded_verts) @@ -165,22 +169,24 @@ def update_railing_modifier_bmesh(context): tool.Blender.apply_bmesh(obj.data, bm) + def get_path_data(obj): si_conversion = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get()) - if obj.mode == 'EDIT': + if obj.mode == "EDIT": # otherwise mesh may not contain all changes # added in edit mode obj.update_from_editmode() mesh = obj.data path_data = dict() - path_data['edges'] = [e.vertices[:] for e in mesh.edges] - path_data['verts'] = [v.co / si_conversion for v in mesh.vertices] + path_data["edges"] = [e.vertices[:] for e in mesh.edges] + path_data["verts"] = [v.co / si_conversion for v in mesh.vertices] - if not path_data['edges'] or not path_data['verts']: + if not path_data["edges"] or not path_data["verts"]: return None return path_data + class BIM_OT_add_railing(Operator): bl_idname = "mesh.add_railing" bl_label = "Railing" @@ -203,9 +209,13 @@ class BIM_OT_add_railing(Operator): obj.location = spawn_location body_context = ifcopenshell.util.representation.get_context(ifc_file, "Model", "Body", "MODEL_VIEW") blenderbim.core.root.assign_class( - tool.Ifc, tool.Collector, tool.Root, obj=obj, - ifc_class="IfcRailing", should_add_representation=True, - context=body_context + tool.Ifc, + tool.Collector, + tool.Root, + obj=obj, + ifc_class="IfcRailing", + should_add_representation=True, + context=body_context, ) bpy.ops.object.select_all(action="DESELECT") bpy.context.view_layer.objects.active = None @@ -242,12 +252,12 @@ class AddRailing(bpy.types.Operator, tool.Ifc.Operator): path_data = { "edges": [[0, 1], [1, 2]], "verts": [ - Vector([-1.0, 0.0, 0.0]) / si_conversion, - Vector([0.0, 0.0, 0.0]) / si_conversion, - Vector([1.0, 0.0, 0.0]) / si_conversion - ] + Vector([-1.0, 0.0, 0.0]) / si_conversion, + Vector([0.0, 0.0, 0.0]) / si_conversion, + Vector([1.0, 0.0, 0.0]) / si_conversion, + ], } - railing_data['path_data'] = path_data + railing_data["path_data"] = path_data update_bbim_railing_pset(element, railing_data) update_railing_modifier_ifc_data(context) @@ -265,7 +275,7 @@ class EnableEditingRailing(bpy.types.Operator, tool.Ifc.Operator): props = obj.BIMRailingProperties element = tool.Ifc.get_entity(obj) data = json.loads(ifcopenshell.util.element.get_pset(element, "BBIM_Railing", "Data")) - data['path_data'] = json.dumps(data['path_data']) + data["path_data"] = json.dumps(data["path_data"]) # required since we could load pset from .ifc and BIMRailingProperties won't be set for prop_name in data: @@ -322,10 +332,10 @@ class FinishEditingRailing(bpy.types.Operator, tool.Ifc.Operator): if not RailingData.is_loaded: RailingData.load() - path_data = RailingData.data["parameters"]['data_dict']['path_data'] + path_data = RailingData.data["parameters"]["data_dict"]["path_data"] railing_data = props.get_general_kwargs() - railing_data['path_data'] = path_data + railing_data["path_data"] = path_data props.is_editing = -1 update_bbim_railing_pset(element, railing_data) @@ -374,11 +384,11 @@ class FinishEditingRailingPath(bpy.types.Operator, tool.Ifc.Operator): railing_data = props.get_general_kwargs() path_data = get_path_data(obj) - railing_data['path_data'] = path_data + railing_data["path_data"] = path_data props.is_editing_path = False update_bbim_railing_pset(element, railing_data) - refresh() # need RailingData to be updated before update_railing_modifier_bmesh + refresh() # need RailingData to be updated before update_railing_modifier_bmesh update_railing_modifier_bmesh(context) return {"FINISHED"} diff --git a/src/blenderbim/blenderbim/bim/module/model/ui.py b/src/blenderbim/blenderbim/bim/module/model/ui.py index 71a5d20d61..3e8d9e8ce5 100644 --- a/src/blenderbim/blenderbim/bim/module/model/ui.py +++ b/src/blenderbim/blenderbim/bim/module/model/ui.py @@ -19,7 +19,15 @@ import bpy import blenderbim.tool as tool from bpy.types import Panel, Operator, Menu -from blenderbim.bim.module.model.data import AuthoringData, ArrayData, StairData, SverchokData, WindowData, DoorData, RailingData +from blenderbim.bim.module.model.data import ( + AuthoringData, + ArrayData, + StairData, + SverchokData, + WindowData, + DoorData, + RailingData, +) 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.window import update_window_modifier_bmesh diff --git a/src/blenderbim/blenderbim/tool/blender.py b/src/blenderbim/blenderbim/tool/blender.py index abaef2cfd9..5efcf891e3 100644 --- a/src/blenderbim/blenderbim/tool/blender.py +++ b/src/blenderbim/blenderbim/tool/blender.py @@ -101,8 +101,10 @@ class Blender: # better to be safe because otherwise mesh won't be updated # and you won't get any errors if not bm.is_wrapped or hash(bmesh.from_edit_mesh(mesh)) != hash(bm): - raise Exception(f'{bm} is not edit mesh for {mesh}. ' - 'For applying bmesh in edit mode bmesh should be acquired with `bmesh.from_edit_mesh(me)`.') + raise Exception( + f"{bm} is not edit mesh for {mesh}. " + "For applying bmesh in edit mode bmesh should be acquired with `bmesh.from_edit_mesh(me)`." + ) bmesh.update_edit_mesh(mesh) else: bm.to_mesh(mesh) @@ -122,4 +124,4 @@ class Blender: bm = bmesh.new() if not clean: bm.from_mesh(mesh) - return bm \ No newline at end of file + return bm