diff --git a/src/blenderbim/blenderbim/bim/module/georeference/operator.py b/src/blenderbim/blenderbim/bim/module/georeference/operator.py index 2026de99e4..12adf164c6 100644 --- a/src/blenderbim/blenderbim/bim/module/georeference/operator.py +++ b/src/blenderbim/blenderbim/bim/module/georeference/operator.py @@ -39,24 +39,7 @@ class EnableEditingGeoreferencing(bpy.types.Operator): props = context.scene.BIMGeoreferenceProperties props.projected_crs.clear() - - for attribute in IfcStore.get_schema().declaration_by_name("IfcProjectedCRS").all_attributes(): - data_type = ifcopenshell.util.attribute.get_primitive_type(attribute) - if data_type == "entity": - continue - new = props.projected_crs.add() - new.name = attribute.name() - new.is_null = Data.projected_crs[attribute.name()] is None - new.is_optional = attribute.optional() - new.data_type = data_type - if data_type == "string": - new.string_value = "" if new.is_null else Data.projected_crs[attribute.name()] - elif data_type == "float": - new.float_value = 0.0 if new.is_null else Data.projected_crs[attribute.name()] - elif data_type == "integer": - new.int_value = 0 if new.is_null else Data.projected_crs[attribute.name()] - elif data_type == "boolean": - new.bool_value = False if new.is_null else Data.projected_crs[attribute.name()] + blenderbim.bim.helper.import_attributes("IfcProjectedCRS", props.projected_crs, Data.projected_crs) props.is_map_unit_null = Data.projected_crs["MapUnit"] is None if not props.is_map_unit_null: @@ -69,18 +52,9 @@ class EnableEditingGeoreferencing(bpy.types.Operator): props.map_unit_imperial = Data.projected_crs["MapUnit"]["Name"] props.map_conversion.clear() - - for attribute in IfcStore.get_schema().declaration_by_name("IfcMapConversion").all_attributes(): - data_type = ifcopenshell.util.attribute.get_primitive_type(attribute) - if data_type == "entity" or data_type == "select": - continue - new = props.map_conversion.add() - new.name = attribute.name() - new.is_null = Data.map_conversion[attribute.name()] is None - new.is_optional = attribute.optional() - # Enforce a string data type to prevent data loss in single-precision Blender props - new.data_type = "string" - new.string_value = "" if new.is_null else str(Data.map_conversion[attribute.name()]) + blenderbim.bim.helper.import_attributes( + "IfcMapConversion", props.map_conversion, Data.map_conversion, self.import_map_conversion_attributes + ) props.has_true_north = bool(Data.true_north) if Data.true_north: @@ -90,6 +64,12 @@ class EnableEditingGeoreferencing(bpy.types.Operator): props.is_editing = True return {"FINISHED"} + def import_map_conversion_attributes(self, name, prop, data): + if prop is not None: + # Enforce a string data type to prevent data loss in single-precision Blender props + prop.data_type = "string" + prop.string_value = "" if prop.is_null else str(data[name]) + return True class DisableEditingGeoreferencing(bpy.types.Operator): bl_idname = "bim.disable_editing_georeferencing" diff --git a/src/blenderbim/blenderbim/bim/module/group/operator.py b/src/blenderbim/blenderbim/bim/module/group/operator.py index 0cd773791f..66044981fb 100644 --- a/src/blenderbim/blenderbim/bim/module/group/operator.py +++ b/src/blenderbim/blenderbim/bim/module/group/operator.py @@ -20,6 +20,7 @@ import bpy import ifcopenshell.util.attribute import ifcopenshell.api +import blenderbim.bim.helper from blenderbim.bim.ifc import IfcStore from ifcopenshell.api.group.data import Data @@ -120,17 +121,8 @@ class EnableEditingGroup(bpy.types.Operator): props = context.scene.BIMGroupProperties props.group_attributes.clear() - data = Data.groups[self.group] + blenderbim.bim.helper.import_attributes("IfcGroup", props.group_attributes, Data.groups[self.group]) - for attribute in IfcStore.get_schema().declaration_by_name("IfcGroup").all_attributes(): - data_type = ifcopenshell.util.attribute.get_primitive_type(attribute) - if data_type == "entity": - continue - new = props.group_attributes.add() - new.name = attribute.name() - new.is_null = data[attribute.name()] is None - new.is_optional = attribute.optional() - new.string_value = "" if new.is_null else data[attribute.name()] props.active_group_id = self.group return {"FINISHED"} diff --git a/src/blenderbim/blenderbim/bim/module/layer/operator.py b/src/blenderbim/blenderbim/bim/module/layer/operator.py index 2ebd391809..2e90fcc583 100644 --- a/src/blenderbim/blenderbim/bim/module/layer/operator.py +++ b/src/blenderbim/blenderbim/bim/module/layer/operator.py @@ -21,6 +21,7 @@ import bpy import json import ifcopenshell.util.attribute import ifcopenshell.api +import blenderbim.bim.helper from blenderbim.bim.ifc import IfcStore from ifcopenshell.api.layer.data import Data @@ -63,17 +64,10 @@ class EnableEditingLayer(bpy.types.Operator): props = context.scene.BIMLayerProperties props.layer_attributes.clear() - data = Data.layers[self.layer] + blenderbim.bim.helper.import_attributes( + "IfcPresentationLayerAssignment", props.layer_attributes, Data.layers[self.layer] + ) - for attribute in IfcStore.get_schema().declaration_by_name("IfcPresentationLayerAssignment").all_attributes(): - data_type = ifcopenshell.util.attribute.get_primitive_type(attribute) - if data_type == "entity" or data_type == "select": - continue - new = props.layer_attributes.add() - new.name = attribute.name() - new.is_null = data[attribute.name()] is None - new.is_optional = attribute.optional() - new.string_value = "" if new.is_null else data[attribute.name()] props.active_layer_id = self.layer return {"FINISHED"} diff --git a/src/blenderbim/blenderbim/bim/module/material/operator.py b/src/blenderbim/blenderbim/bim/module/material/operator.py index e735461ef8..383f9866da 100644 --- a/src/blenderbim/blenderbim/bim/module/material/operator.py +++ b/src/blenderbim/blenderbim/bim/module/material/operator.py @@ -429,14 +429,7 @@ class EnableEditingAssignedMaterial(bpy.types.Operator): props.material_set_attributes.clear() - for attribute in IfcStore.get_schema().declaration_by_name(material_set_class).all_attributes(): - if "" not in str(attribute.type_of_attribute): - continue - if attribute.name() in material_set_data: - new = props.material_set_attributes.add() - new.name = attribute.name() - new.is_null = material_set_data[attribute.name()] is None - new.string_value = "" if new.is_null else material_set_data[attribute.name()] + blenderbim.bim.helper.import_attributes(material_set_class, props.material_set_attributes, material_set_data) return {"FINISHED"} def import_attributes(self, name, prop, data): @@ -508,10 +501,7 @@ class EditAssignedMaterial(bpy.types.Operator): return {"FINISHED"} material_set = self.file.by_id(self.material_set) - - attributes = {} - for attribute in props.material_set_attributes: - attributes[attribute.name] = None if attribute.is_null else attribute.string_value + attributes = blenderbim.bim.helper.export_attributes(props.material_set_attributes) ifcopenshell.api.run( "material.edit_assigned_material", self.file, @@ -610,35 +600,15 @@ class EnableEditingMaterialSetItem(bpy.types.Operator): profile = self.file.by_id(material_set_item_data["Profile"]) profile_data = ProfileData.profiles[material_set_item_data["Profile"]] + props = self.props.material_set_item_profile_attributes - for attribute in IfcStore.get_schema().declaration_by_name(profile.is_a()).all_attributes(): - data_type = ifcopenshell.util.attribute.get_primitive_type(attribute) - if data_type == "entity": - continue - if attribute.name() in profile_data: - new = self.props.material_set_item_profile_attributes.add() - new.name = attribute.name() - new.is_null = profile_data[attribute.name()] is None - new.is_optional = attribute.optional() - new.data_type = data_type - if data_type == "string": - new.string_value = "" if new.is_null else profile_data[attribute.name()] - elif data_type == "float": - new.float_value = 0.0 if new.is_null else profile_data[attribute.name()] - elif data_type == "integer": - new.int_value = 0 if new.is_null else profile_data[attribute.name()] - elif data_type == "boolean": - new.bool_value = False if new.is_null else profile_data[attribute.name()] - elif data_type == "enum": - new.enum_items = json.dumps(ifcopenshell.util.attribute.get_enum_items(attribute)) - if profile_data[attribute.name()]: - new.enum_value = profile_data[attribute.name()] - - # Force null to be false if the attribute is mandatory because when we first assign a profile, all of - # its fields are null (which is illegal). - # TODO: find a better solution. - if not new.is_optional: - new.is_null = False + blenderbim.bim.helper.import_attributes(profile.is_a(), props, profile_data) + for prop in props: + # Force null to be false if the attribute is mandatory because when we first assign a profile, all of + # its fields are null (which is illegal). + # TODO: find a better solution. + if not prop.is_optional: + prop.is_null = False class DisableEditingMaterialSetItem(bpy.types.Operator): diff --git a/src/blenderbim/blenderbim/bim/module/system/operator.py b/src/blenderbim/blenderbim/bim/module/system/operator.py index 51597aa7c0..f6eba6dfc1 100644 --- a/src/blenderbim/blenderbim/bim/module/system/operator.py +++ b/src/blenderbim/blenderbim/bim/module/system/operator.py @@ -20,6 +20,7 @@ import bpy import ifcopenshell.util.attribute import ifcopenshell.api +import blenderbim.bim.helper from blenderbim.bim.ifc import IfcStore from ifcopenshell.api.system.data import Data @@ -120,17 +121,7 @@ class EnableEditingSystem(bpy.types.Operator): props = context.scene.BIMSystemProperties props.system_attributes.clear() - data = Data.systems[self.system] - - for attribute in IfcStore.get_schema().declaration_by_name("IfcSystem").all_attributes(): - data_type = ifcopenshell.util.attribute.get_primitive_type(attribute) - if data_type == "entity": - continue - new = props.system_attributes.add() - new.name = attribute.name() - new.is_null = data[attribute.name()] is None - new.is_optional = attribute.optional() - new.string_value = "" if new.is_null else data[attribute.name()] + blenderbim.bim.helper.import_attributes("IfcSystem", props.system_attributes, Data.systems[self.system]) props.active_system_id = self.system return {"FINISHED"}