diff --git a/src/blenderbim/blenderbim/bim/module/model/data.py b/src/blenderbim/blenderbim/bim/module/model/data.py index 213527ab26..b307eb742f 100644 --- a/src/blenderbim/blenderbim/bim/module/model/data.py +++ b/src/blenderbim/blenderbim/bim/module/model/data.py @@ -19,11 +19,11 @@ import bpy import math import json -import functools import ifcopenshell import ifcopenshell.util.element from ifcopenshell.util.doc import get_entity_doc, get_predefined_type_doc import blenderbim.tool as tool +from math import degrees def refresh(): @@ -371,26 +371,27 @@ class RailingData: @classmethod def pset_data(cls): - return tool.Model.get_railing_pset_data(bpy.context.active_object) + return tool.Model.get_modeling_bbim_pset_data(bpy.context.active_object, "BBIM_Railing") @classmethod def general_params(cls): props = bpy.context.active_object.BIMRailingProperties - railing_data = cls.data["parameters"]["data_dict"] + data = cls.data["parameters"]["data_dict"] general_params = {} - general_props = props.get_general_kwargs(railing_type=railing_data["railing_type"]) + general_props = props.get_general_kwargs(railing_type=data["railing_type"]) for prop_name in general_props: - prop_value = railing_data[prop_name] + prop_value = data[prop_name] prop_value = round(prop_value, 5) if type(prop_value) is float else prop_value prop_readable_name = props.bl_rna.properties[prop_name].name general_params[prop_readable_name] = prop_value return general_params - + @classmethod def path_data(cls): return cls.data["parameters"]["data_dict"]["path_data"] + class RoofData: data = {} is_loaded = False @@ -398,14 +399,27 @@ class RoofData: @classmethod def load(cls): cls.is_loaded = True - cls.data = {"parameters": cls.parameters()} + cls.data = {} + cls.data["parameters"] = cls.pset_data() + cls.data["general_params"] = cls.general_params() @classmethod - def parameters(cls): - element = tool.Ifc.get_entity(bpy.context.active_object) - if element: - psets = ifcopenshell.util.element.get_psets(element) - parameters = psets.get("BBIM_Roof", None) - if parameters: - parameters["data_dict"] = json.loads(parameters.get("Data", "[]") or "[]") - return parameters + def pset_data(cls): + return tool.Model.get_modeling_bbim_pset_data(bpy.context.active_object, "BBIM_Roof") + + @classmethod + def general_params(cls): + props = bpy.context.active_object.BIMRoofProperties + data = cls.data["parameters"]["data_dict"] + general_params = {} + general_props = props.get_general_kwargs(generation_method=data["generation_method"]) + for prop_name in general_props: + prop_value = data[prop_name] + prop_value = round(prop_value, 5) if type(prop_value) is float else prop_value + + if prop_name in ("angle", "rafter_edge_angle"): + prop_value = round(degrees(prop_value), 2) + + prop_readable_name = props.bl_rna.properties[prop_name].name + general_params[prop_readable_name] = prop_value + return general_params diff --git a/src/blenderbim/blenderbim/bim/module/model/prop.py b/src/blenderbim/blenderbim/bim/module/model/prop.py index 7f8a2b52d9..13cd957db5 100644 --- a/src/blenderbim/blenderbim/bim/module/model/prop.py +++ b/src/blenderbim/blenderbim/bim/module/model/prop.py @@ -629,7 +629,7 @@ class BIMRoofProperties(PropertyGroup): ("ANGLE", "ANGLE", ""), ) - is_editing: bpy.props.IntProperty(default=-1) + is_editing: bpy.props.BoolProperty(default=False) is_editing_path: bpy.props.BoolProperty(default=False) roof_type: bpy.props.EnumProperty(name="Roof Type", items=roof_types, default="HIP/GABLE ROOF") @@ -643,14 +643,16 @@ class BIMRoofProperties(PropertyGroup): roof_thickness: bpy.props.FloatProperty(name="Roof Thickness", default=0.1, subtype="DISTANCE") rafter_edge_angle: bpy.props.FloatProperty(name="Rafter Edge Angle", min=0, max=pi, default=pi / 2, subtype="ANGLE") - def get_general_kwargs(self, convert_to_project_units=False): + def get_general_kwargs(self, generation_method=None, convert_to_project_units=False): + if generation_method is None: + generation_method = self.generation_method kwargs = { "roof_type": self.roof_type, - "generation_method": self.generation_method, + "generation_method": generation_method, "roof_thickness": self.roof_thickness, "rafter_edge_angle": self.rafter_edge_angle, } - if self.generation_method == "HEIGHT": + if generation_method == "HEIGHT": kwargs["height"] = self.height else: kwargs["angle"] = self.angle diff --git a/src/blenderbim/blenderbim/bim/module/model/railing.py b/src/blenderbim/blenderbim/bim/module/model/railing.py index 32fcb9c741..628a2baa3a 100644 --- a/src/blenderbim/blenderbim/bim/module/model/railing.py +++ b/src/blenderbim/blenderbim/bim/module/model/railing.py @@ -80,7 +80,7 @@ def update_railing_modifier_ifc_data(context): if props.railing_type == "WALL_MOUNTED_HANDRAIL": body = ifcopenshell.util.representation.get_context(ifc_file, "Model", "Body", "MODEL_VIEW") - pset_data = tool.Model.get_railing_pset_data(bpy.context.active_object) + pset_data = tool.Model.get_modeling_bbim_pset_data(bpy.context.active_object, "BBIM_Railing") path_data = pset_data["data_dict"]["path_data"] railing_path = [Vector(v) for v in path_data["verts"]] si_conversion = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get()) @@ -117,6 +117,9 @@ def update_bbim_railing_pset(element, railing_data): def update_railing_modifier_bmesh(context): + """before using should make sure that Data contains up-to-date information. + If BBIM Pset just changed should call refresh() before updating bmesh + """ obj = context.object props = obj.BIMRailingProperties @@ -394,7 +397,7 @@ class FinishEditingRailing(bpy.types.Operator, tool.Ifc.Operator): element = tool.Ifc.get_entity(obj) props = obj.BIMRailingProperties - pset_data = tool.Model.get_railing_pset_data(bpy.context.active_object) + pset_data = tool.Model.get_modeling_bbim_pset_data(bpy.context.active_object, "BBIM_Railing") path_data = pset_data["data_dict"]["path_data"] railing_data = props.get_general_kwargs(convert_to_project_units=True) @@ -417,7 +420,7 @@ class FlipRailingPathOrder(bpy.types.Operator, tool.Ifc.Operator): element = tool.Ifc.get_entity(obj) props = obj.BIMRailingProperties - pset_data = tool.Model.get_railing_pset_data(bpy.context.active_object) + pset_data = tool.Model.get_modeling_bbim_pset_data(bpy.context.active_object, "BBIM_Railing") path_data = pset_data["data_dict"]["path_data"] # flip the vertex order and edges diff --git a/src/blenderbim/blenderbim/bim/module/model/roof.py b/src/blenderbim/blenderbim/bim/module/model/roof.py index ce8b0e3ba2..8b9a836337 100644 --- a/src/blenderbim/blenderbim/bim/module/model/roof.py +++ b/src/blenderbim/blenderbim/bim/module/model/roof.py @@ -383,20 +383,6 @@ def bm_get_indices(sequence): return [i.index for i in sequence] -def roof_is_gabled(): - if not RoofData.is_loaded: - RoofData.load() - - path_data = RoofData.parameters()["data_dict"]["path_data"] - angle_layer = path_data.get("gable_roof_angles", None) - if not angle_layer: - return False - for edge_angle in angle_layer: - if float_is_zero(edge_angle - pi / 2): - return True - return False - - def update_roof_modifier_ifc_data(context): """should be called after new geometry settled since it's going to update ifc representation @@ -405,6 +391,17 @@ def update_roof_modifier_ifc_data(context): props = obj.BIMRoofProperties element = tool.Ifc.get_entity(obj) + def roof_is_gabled(): + pset_data = tool.Model.get_modeling_bbim_pset_data(obj, "BBIM_Roof") + path_data = pset_data["data_dict"]["path_data"] + angle_layer = path_data.get("gable_roof_angles", None) + if not angle_layer: + return False + for edge_angle in angle_layer: + if float_is_zero(edge_angle - pi / 2): + return True + return False + # type attributes if props.roof_type == "HIP/GABLE ROOF": element.PredefinedType = "GABLE_ROOF" if roof_is_gabled() else "HIP_ROOF" @@ -424,9 +421,13 @@ def update_bbim_roof_pset(element, roof_data): def update_roof_modifier_bmesh(context): + """before using should make sure that Data contains up-to-date information. + If BBIM Pset just changed should call refresh() before updating bmesh + """ obj = context.object props = obj.BIMRoofProperties + # NOTE: using Data since bmesh update will hapen very often if not RoofData.is_loaded: RoofData.load() path_data = RoofData.data["parameters"]["data_dict"]["path_data"] @@ -596,7 +597,7 @@ class EnableEditingRoof(bpy.types.Operator, tool.Ifc.Operator): data = json.loads(ifcopenshell.util.element.get_pset(element, "BBIM_Roof", "Data")) # required since we could load pset from .ifc and BIMRoofProperties won't be set props.set_props_kwargs_from_ifc_data(data) - props.is_editing = 1 + props.is_editing = True return {"FINISHED"} @@ -624,7 +625,7 @@ class CancelEditingRoof(bpy.types.Operator, tool.Ifc.Operator): should_sync_changes_first=False, ) - props.is_editing = -1 + props.is_editing = False return {"FINISHED"} @@ -638,13 +639,12 @@ class FinishEditingRoof(bpy.types.Operator, tool.Ifc.Operator): element = tool.Ifc.get_entity(obj) props = obj.BIMRoofProperties - if not RoofData.is_loaded: - RoofData.load() - path_data = RoofData.data["parameters"]["data_dict"]["path_data"] + pset_data = tool.Model.get_modeling_bbim_pset_data(obj, "BBIM_Roof") + path_data = pset_data["data_dict"]["path_data"] roof_data = props.get_general_kwargs(convert_to_project_units=True) roof_data["path_data"] = path_data - props.is_editing = -1 + props.is_editing = False update_bbim_roof_pset(element, roof_data) update_roof_modifier_ifc_data(context) @@ -769,9 +769,8 @@ class RemoveRoof(bpy.types.Operator, tool.Ifc.Operator): def _execute(self, context): obj = context.active_object - props = obj.BIMRoofProperties element = tool.Ifc.get_entity(obj) - obj.BIMRoofProperties.is_editing = -1 + obj.BIMRoofProperties.is_editing = False pset = tool.Pset.get_element_pset(element, "BBIM_Roof") ifcopenshell.api.run("pset.remove_pset", tool.Ifc.get(), pset=pset) diff --git a/src/blenderbim/blenderbim/bim/module/model/ui.py b/src/blenderbim/blenderbim/bim/module/model/ui.py index 1e88fb782f..fc29b7f73e 100644 --- a/src/blenderbim/blenderbim/bim/module/model/ui.py +++ b/src/blenderbim/blenderbim/bim/module/model/ui.py @@ -18,7 +18,7 @@ import bpy import blenderbim.tool as tool -from bpy.types import Panel, Operator, Menu +from bpy.types import Panel, Menu from blenderbim.bim.module.model.data import ( AuthoringData, ArrayData, @@ -36,7 +36,6 @@ 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.roof import update_roof_modifier_bmesh from blenderbim.bim.helper import prop_with_search -from math import degrees class LaunchTypeManager(bpy.types.Operator): @@ -191,7 +190,7 @@ class BIM_PT_array(bpy.types.Panel): op.parent = ArrayData.data["parameters"]["Parent"] op = row.operator("bim.select_all_array_objects", icon="RESTRICT_SELECT_OFF", text="") op.parent = ArrayData.data["parameters"]["Parent"] - + if ArrayData.data["parameters"]["data_dict"]: row.operator("bim.add_array", icon="ADD", text="") @@ -619,7 +618,7 @@ class BIM_PT_roof(bpy.types.Panel): roof_data = RoofData.data["parameters"]["data_dict"] - if props.is_editing != -1: + if props.is_editing: row = self.layout.row(align=True) row.operator("bim.finish_editing_roof", icon="CHECKMARK", text="Finish Editing") row.operator("bim.cancel_editing_roof", icon="CANCEL", text="") @@ -640,14 +639,9 @@ class BIM_PT_roof(bpy.types.Panel): row.operator("bim.remove_roof", icon="X", text="") box = self.layout.box() - general_props = props.get_general_kwargs() - for prop in general_props: - prop_value = roof_data[prop] - prop_value = round(prop_value, 5) if type(prop_value) is float else prop_value + for prop_name, prop_value in RoofData.data["general_params"].items(): row = box.row(align=True) - row.label(text=f"{props.bl_rna.properties[prop].name}") - if prop in ("angle", "rafter_edge_angle"): - prop_value = round(degrees(prop_value), 2) + row.label(text=prop_name) row.label(text=str(prop_value)) else: row = self.layout.row() diff --git a/src/blenderbim/blenderbim/tool/model.py b/src/blenderbim/blenderbim/tool/model.py index ed8f5b15d1..2bd74e8762 100644 --- a/src/blenderbim/blenderbim/tool/model.py +++ b/src/blenderbim/blenderbim/tool/model.py @@ -737,12 +737,13 @@ class Model(blenderbim.core.tool.Model): AuthoringData.type_thumbnails[element.id()] = obj.preview.icon_id @classmethod - def get_railing_pset_data(cls, object): + def get_modeling_bbim_pset_data(cls, object, pset_name): + """get modelling BBIM pset data (eg, BBIM_Roof) and loads it's `Data` as json to `data_dict`""" element = tool.Ifc.get_entity(object) if not element: return psets = ifcopenshell.util.element.get_psets(element) - pset_data = psets.get("BBIM_Railing", None) + pset_data = psets.get(pset_name, None) if not pset_data: return pset_data["data_dict"] = json.loads(pset_data.get("Data", "[]") or "[]")