RailingData use refactor, solves #3416

This commit is contained in:
Andrej730
2023-07-12 16:33:45 +05:00
parent bc909a26fa
commit 56adfc70b5
6 changed files with 72 additions and 50 deletions
@@ -23,7 +23,6 @@ import blenderbim.tool as tool
from blenderbim.bim.helper import prop_with_search from blenderbim.bim.helper import prop_with_search
from bpy.types import WorkSpaceTool from bpy.types import WorkSpaceTool
# from blenderbim.bim.module.model.data import AuthoringData, RailingData, RoofData
from blenderbim.bim.module.drawing.prop import ANNOTATION_TYPES_DATA from blenderbim.bim.module.drawing.prop import ANNOTATION_TYPES_DATA
from blenderbim.bim.module.drawing.data import DecoratorData, AnnotationData from blenderbim.bim.module.drawing.data import DecoratorData, AnnotationData
from blenderbim.bim.ifc import IfcStore from blenderbim.bim.ifc import IfcStore
@@ -108,7 +107,6 @@ class LaunchAnnotationTypeManager(bpy.types.Operator):
op.element = relating_type["id"] op.element = relating_type["id"]
class AnnotationTool(WorkSpaceTool): class AnnotationTool(WorkSpaceTool):
bl_space_type = "VIEW_3D" bl_space_type = "VIEW_3D"
bl_context_mode = "OBJECT" bl_context_mode = "OBJECT"
@@ -364,17 +364,27 @@ class RailingData:
@classmethod @classmethod
def load(cls): def load(cls):
cls.is_loaded = True 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 @classmethod
def parameters(cls): def pset_data(cls):
element = tool.Ifc.get_entity(bpy.context.active_object) return tool.Model.get_railing_pset_data(bpy.context.active_object)
if element:
psets = ifcopenshell.util.element.get_psets(element) @classmethod
parameters = psets.get("BBIM_Railing", None) def general_params(cls):
if parameters: props = bpy.context.active_object.BIMRailingProperties
parameters["data_dict"] = json.loads(parameters.get("Data", "[]") or "[]") railing_data = cls.data["parameters"]["data_dict"]
return parameters general_params = {}
general_props = props.get_general_kwargs(railing_type=railing_data["railing_type"])
for prop_name in general_props:
prop_value = railing_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
class RoofData: class RoofData:
@@ -432,13 +432,13 @@ class BIMDoorProperties(PropertyGroup):
name="Transom Thickness", name="Transom Thickness",
description="Set values > 0 to add a transom.\n" "`0.050 mm` is good as default value", description="Set values > 0 to add a transom.\n" "`0.050 mm` is good as default value",
default=0.000, default=0.000,
subtype="DISTANCE" subtype="DISTANCE",
) )
transom_offset: bpy.props.FloatProperty( transom_offset: bpy.props.FloatProperty(
name="Transom Offset", name="Transom Offset",
description="Distance from the bottom door opening to the beginning of the transom (unlike windows)", description="Distance from the bottom door opening to the beginning of the transom (unlike windows)",
default=1.525, default=1.525,
subtype="DISTANCE" subtype="DISTANCE",
) )
casing_thickness: bpy.props.FloatProperty( casing_thickness: bpy.props.FloatProperty(
@@ -547,7 +547,7 @@ class BIMRailingProperties(PropertyGroup):
("NONE", "NONE", ""), ("NONE", "NONE", ""),
) )
is_editing: bpy.props.IntProperty(default=-1) is_editing: bpy.props.BoolProperty(default=False)
is_editing_path: bpy.props.BoolProperty(default=False) is_editing_path: bpy.props.BoolProperty(default=False)
railing_type: bpy.props.EnumProperty(name="Railing Type", items=railing_types, default="FRAMELESS_PANEL") railing_type: bpy.props.EnumProperty(name="Railing Type", items=railing_types, default="FRAMELESS_PANEL")
@@ -563,29 +563,36 @@ class BIMRailingProperties(PropertyGroup):
"If disabled, supports are added automatically based on the support spacing", "If disabled, supports are added automatically based on the support spacing",
) )
support_spacing: bpy.props.FloatProperty( support_spacing: bpy.props.FloatProperty(
name="Support Spacing", name="Support Spacing",
default=1.0, default=1.0,
min=0.01, min=0.01,
description="Distance between supports if automatic supports are used", description="Distance between supports if automatic supports are used",
subtype="DISTANCE",
) )
railing_diameter: bpy.props.FloatProperty(name="Railing Diameter", default=0.050) railing_diameter: bpy.props.FloatProperty(name="Railing Diameter", default=0.050, subtype="DISTANCE")
clear_width: bpy.props.FloatProperty( clear_width: bpy.props.FloatProperty(
name="Clear Width", default=0.040, description="Clear width between the railing and the wall" name="Clear Width",
default=0.040,
description="Clear width between the railing and the wall",
subtype="DISTANCE",
) )
terminal_type: bpy.props.EnumProperty(name="Terminal Type", items=cap_types, default="180") terminal_type: bpy.props.EnumProperty(name="Terminal Type", items=cap_types, default="180")
def get_general_kwargs(self, convert_to_project_units=False): def get_general_kwargs(self, railing_type=None, convert_to_project_units=False):
if railing_type is None:
railing_type = self.railing_type
base_kwargs = { base_kwargs = {
"railing_type": self.railing_type, "railing_type": railing_type,
"height": self.height, "height": self.height,
} }
additional_kwargs = {} additional_kwargs = {}
if self.railing_type == "FRAMELESS_PANEL": if railing_type == "FRAMELESS_PANEL":
additional_kwargs = { additional_kwargs = {
"thickness": self.thickness, "thickness": self.thickness,
"spacing": self.spacing, "spacing": self.spacing,
} }
elif self.railing_type == "WALL_MOUNTED_HANDRAIL": elif railing_type == "WALL_MOUNTED_HANDRAIL":
additional_kwargs = { additional_kwargs = {
"railing_diameter": self.railing_diameter, "railing_diameter": self.railing_diameter,
"clear_width": self.clear_width, "clear_width": self.clear_width,
@@ -606,6 +613,7 @@ class BIMRailingProperties(PropertyGroup):
for prop_name in kwargs: for prop_name in kwargs:
setattr(self, prop_name, kwargs[prop_name]) setattr(self, prop_name, kwargs[prop_name])
class BIMRoofProperties(PropertyGroup): class BIMRoofProperties(PropertyGroup):
non_si_units_props = ( non_si_units_props = (
"is_editing", "is_editing",
@@ -23,14 +23,12 @@ import ifcopenshell
from ifcopenshell.util.shape_builder import V from ifcopenshell.util.shape_builder import V
import blenderbim import blenderbim
import blenderbim.tool as tool import blenderbim.tool as tool
from blenderbim.bim.helper import convert_property_group_from_si
from blenderbim.bim.ifc import IfcStore from blenderbim.bim.ifc import IfcStore
from blenderbim.bim.module.model.door import bm_sort_out_geom from blenderbim.bim.module.model.door import bm_sort_out_geom
from blenderbim.bim.module.model.data import RailingData, refresh from blenderbim.bim.module.model.data import RailingData, refresh
from blenderbim.bim.module.model.decorator import ProfileDecorator from blenderbim.bim.module.model.decorator import ProfileDecorator
from mathutils import Vector, Matrix from mathutils import Vector
from pprint import pprint
import json import json
# reference: # reference:
@@ -38,7 +36,6 @@ import json
# https://ifc43-docs.standards.buildingsmart.org/IFC/RELEASE/IFC4x3/HTML/lexical/IfcRailingType.htm # https://ifc43-docs.standards.buildingsmart.org/IFC/RELEASE/IFC4x3/HTML/lexical/IfcRailingType.htm
def bm_split_edge_at_offset(edge, offset): def bm_split_edge_at_offset(edge, offset):
v0, v1 = edge.verts v0, v1 = edge.verts
@@ -83,7 +80,9 @@ def update_railing_modifier_ifc_data(context):
if props.railing_type == "WALL_MOUNTED_HANDRAIL": if props.railing_type == "WALL_MOUNTED_HANDRAIL":
body = ifcopenshell.util.representation.get_context(ifc_file, "Model", "Body", "MODEL_VIEW") body = ifcopenshell.util.representation.get_context(ifc_file, "Model", "Body", "MODEL_VIEW")
railing_path = [Vector(v) for v in RailingData.data["parameters"]["data_dict"]["path_data"]["verts"]] pset_data = tool.Model.get_railing_pset_data(bpy.context.active_object)
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()) si_conversion = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
representation_data = { representation_data = {
@@ -121,6 +120,7 @@ def update_railing_modifier_bmesh(context):
obj = context.object obj = context.object
props = obj.BIMRailingProperties props = obj.BIMRailingProperties
# NOTE: using Data since bmesh update will hapen very often
if not RailingData.is_loaded: if not RailingData.is_loaded:
RailingData.load() RailingData.load()
path_data = RailingData.data["parameters"]["data_dict"]["path_data"] path_data = RailingData.data["parameters"]["data_dict"]["path_data"]
@@ -198,7 +198,7 @@ def update_railing_modifier_bmesh(context):
bmesh.ops.dissolve_verts(bm, verts=verts_to_dissolve) bmesh.ops.dissolve_verts(bm, verts=verts_to_dissolve)
# to remove unnecessary verts in 0 spacing case # to remove unnecessary verts in 0 spacing case
bmesh.ops.remove_doubles(bm, verts=bm.verts, dist=0.0001) bmesh.ops.remove_doubles(bm, verts=bm.verts, dist=0.0001)
bmesh.ops.recalc_face_normals(bm, faces=bm.faces[:]) bmesh.ops.recalc_face_normals(bm, faces=bm.faces[:])
tool.Blender.apply_bmesh(obj.data, bm) tool.Blender.apply_bmesh(obj.data, bm)
@@ -317,7 +317,6 @@ class AddRailing(bpy.types.Operator, tool.Ifc.Operator):
self.report({"ERROR"}, "Object has to be IfcRailing/IfcRailingType type to add a railing.") self.report({"ERROR"}, "Object has to be IfcRailing/IfcRailingType type to add a railing.")
return {"CANCELLED"} return {"CANCELLED"}
railing_data = props.get_general_kwargs(convert_to_project_units=True) railing_data = props.get_general_kwargs(convert_to_project_units=True)
path_data = get_path_data(obj) path_data = get_path_data(obj)
if not path_data: if not path_data:
@@ -353,7 +352,7 @@ class EnableEditingRailing(bpy.types.Operator, tool.Ifc.Operator):
# required since we could load pset from .ifc and BIMRailingProperties won't be set # required since we could load pset from .ifc and BIMRailingProperties won't be set
props.set_props_kwargs_from_ifc_data(data) props.set_props_kwargs_from_ifc_data(data)
props.is_editing = 1 props.is_editing = True
return {"FINISHED"} return {"FINISHED"}
@@ -381,7 +380,7 @@ class CancelEditingRailing(bpy.types.Operator, tool.Ifc.Operator):
should_sync_changes_first=False, should_sync_changes_first=False,
) )
props.is_editing = -1 props.is_editing = False
return {"FINISHED"} return {"FINISHED"}
@@ -395,13 +394,12 @@ class FinishEditingRailing(bpy.types.Operator, tool.Ifc.Operator):
element = tool.Ifc.get_entity(obj) element = tool.Ifc.get_entity(obj)
props = obj.BIMRailingProperties props = obj.BIMRailingProperties
if not RailingData.is_loaded: pset_data = tool.Model.get_railing_pset_data(bpy.context.active_object)
RailingData.load() path_data = pset_data["data_dict"]["path_data"]
path_data = RailingData.data["parameters"]["data_dict"]["path_data"]
railing_data = props.get_general_kwargs(convert_to_project_units=True) railing_data = props.get_general_kwargs(convert_to_project_units=True)
railing_data["path_data"] = path_data railing_data["path_data"] = path_data
props.is_editing = -1 props.is_editing = False
update_bbim_railing_pset(element, railing_data) update_bbim_railing_pset(element, railing_data)
update_railing_modifier_ifc_data(context) update_railing_modifier_ifc_data(context)
@@ -419,9 +417,8 @@ class FlipRailingPathOrder(bpy.types.Operator, tool.Ifc.Operator):
element = tool.Ifc.get_entity(obj) element = tool.Ifc.get_entity(obj)
props = obj.BIMRailingProperties props = obj.BIMRailingProperties
if not RailingData.is_loaded: pset_data = tool.Model.get_railing_pset_data(bpy.context.active_object)
RailingData.load() path_data = pset_data["data_dict"]["path_data"]
path_data = RailingData.data["parameters"]["data_dict"]["path_data"]
# flip the vertex order and edges # flip the vertex order and edges
path_data["verts"] = path_data["verts"][::-1] path_data["verts"] = path_data["verts"][::-1]
@@ -497,7 +494,9 @@ class FinishEditingRailingPath(bpy.types.Operator, tool.Ifc.Operator):
props.is_editing_path = False props.is_editing_path = False
update_bbim_railing_pset(element, railing_data) update_bbim_railing_pset(element, railing_data)
refresh() # RailingData has to be updated before run update_railing_modifier_bmesh # RailingData has to be updated before run update_railing_modifier_bmesh
# since we know that BBIM_Railing could have changed
refresh()
update_railing_modifier_bmesh(context) update_railing_modifier_bmesh(context)
if bpy.context.object.mode == "EDIT": if bpy.context.object.mode == "EDIT":
bpy.ops.object.mode_set(mode="OBJECT") bpy.ops.object.mode_set(mode="OBJECT")
@@ -512,9 +511,8 @@ class RemoveRailing(bpy.types.Operator, tool.Ifc.Operator):
def _execute(self, context): def _execute(self, context):
obj = context.active_object obj = context.active_object
props = obj.BIMRailingProperties
element = tool.Ifc.get_entity(obj) element = tool.Ifc.get_entity(obj)
obj.BIMRailingProperties.is_editing = -1 obj.BIMRailingProperties.is_editing = False
pset = tool.Pset.get_element_pset(element, "BBIM_Railing") pset = tool.Pset.get_element_pset(element, "BBIM_Railing")
ifcopenshell.api.run("pset.remove_pset", tool.Ifc.get(), pset=pset) ifcopenshell.api.run("pset.remove_pset", tool.Ifc.get(), pset=pset)
@@ -552,9 +552,7 @@ class BIM_PT_railing(bpy.types.Panel):
row = self.layout.row(align=True) row = self.layout.row(align=True)
row.label(text="Railing parameters", icon="OUTLINER_OB_LATTICE") row.label(text="Railing parameters", icon="OUTLINER_OB_LATTICE")
railing_data = RailingData.data["parameters"]["data_dict"] if props.is_editing:
if props.is_editing != -1:
row = self.layout.row(align=True) row = self.layout.row(align=True)
row.operator("bim.finish_editing_railing", icon="CHECKMARK", text="Finish Editing") row.operator("bim.finish_editing_railing", icon="CHECKMARK", text="Finish Editing")
row.operator("bim.cancel_editing_railing", icon="CANCEL", text="") row.operator("bim.cancel_editing_railing", icon="CANCEL", text="")
@@ -577,18 +575,15 @@ class BIM_PT_railing(bpy.types.Panel):
else: else:
row.operator("bim.enable_editing_railing", icon="GREASEPENCIL", text="") row.operator("bim.enable_editing_railing", icon="GREASEPENCIL", text="")
row.operator("bim.enable_editing_railing_path", icon="ANIM", text="") row.operator("bim.enable_editing_railing_path", icon="ANIM", text="")
# TODO: good for preview but probably should move to .is_editing == -1 # TODO: good for preview but probably should move to .is_editing == True
# since it's writing to ifc # since it's writing to ifc
row.operator("bim.flip_railing_path_order", icon="ARROW_LEFTRIGHT", text="") row.operator("bim.flip_railing_path_order", icon="ARROW_LEFTRIGHT", text="")
row.operator("bim.remove_railing", icon="X", text="") row.operator("bim.remove_railing", icon="X", text="")
box = self.layout.box() box = self.layout.box()
general_props = props.get_general_kwargs() for prop_name, prop_value in RailingData.data["general_params"].items():
for prop in general_props:
prop_value = railing_data[prop]
prop_value = round(prop_value, 5) if type(prop_value) is float else prop_value
row = box.row(align=True) row = box.row(align=True)
row.label(text=f"{props.bl_rna.properties[prop].name}") row.label(text=prop_name)
row.label(text=str(prop_value)) row.label(text=str(prop_value))
else: else:
row = self.layout.row() row = self.layout.row()
+13
View File
@@ -30,6 +30,7 @@ from blenderbim.bim import import_ifc
from blenderbim.bim.module.geometry.helper import Helper from blenderbim.bim.module.geometry.helper import Helper
import collections import collections
from blenderbim.bim.module.model.data import AuthoringData from blenderbim.bim.module.model.data import AuthoringData
import json
class Model(blenderbim.core.tool.Model): class Model(blenderbim.core.tool.Model):
@@ -734,3 +735,15 @@ class Model(blenderbim.core.tool.Model):
obj.preview.image_pixels_float = pixels obj.preview.image_pixels_float = pixels
AuthoringData.type_thumbnails[element.id()] = obj.preview.icon_id AuthoringData.type_thumbnails[element.id()] = obj.preview.icon_id
@classmethod
def get_railing_pset_data(cls, object):
element = tool.Ifc.get_entity(object)
if not element:
return
psets = ifcopenshell.util.element.get_psets(element)
pset_data = psets.get("BBIM_Railing", None)
if not pset_data:
return
pset_data["data_dict"] = json.loads(pset_data.get("Data", "[]") or "[]")
return pset_data